P3398 仓鼠找sugar

LCA的基本操作,

判断两条路径是否相交,如果相交,记 x=lca(a,b)y=lca(c,d),则必有xc~d路径上或y在a~b路径上

若有一个点在某条路径上,那么该点到路径两端点的距离和等于两端点的距离,距离用lca和深度就可以了

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
const int maxn=100010;
int n,m,p,q,cnt;
int head[maxn],dep[maxn],fa[maxn][30];
struct node{
    int to,nxt;
}e[200100];
inline int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
void add(int from,int to){
    cnt++;
    e[cnt].to=to;
    e[cnt].nxt=head[from];
    head[from]=cnt;
}
void dfs(int rt,int f){
    dep[rt]=dep[f]+1;
    fa[rt][0]=f;
    for(int i=1;(1<<i)<=dep[rt];++i)
        fa[rt][i]=fa[fa[rt][i-1]][i-1];
    for(int i=head[rt];i;i=e[i].nxt)
        if(e[i].to!=f)
            dfs(e[i].to,rt);
}
int lca(int x,int y){
    if(dep[x]>dep[y])swap(x,y);
    for(int i=20;i>=0;i--)
        if(dep[x]<=dep[fa[y][i]])y=fa[y][i];
    if(x==y)return x;
    for(int i=20;i>=0;i--){
        if(fa[x][i]==fa[y][i])continue;
        x=fa[x][i];
        y=fa[y][i];
    }
    return fa[x][0];
}
int dis(int x,int y){
    int dd=lca(x,y);
    return abs(dep[x]-dep[dd])+abs(dep[y]-dep[dd]);
}
int main(){
    n=read();m=read();
    int x,y;
    for(int i=1;i<n;++i){
        x=read();y=read();
        add(x,y);add(y,x);
    }
    dfs(1,0);
    int z,k;
    for(int i=1;i<=m;++i){
        x=read();y=read();z=read();k=read();
        p=lca(x,y);
        q=lca(z,k);
        if(dis(z,p)+dis(k,p)==dis(z,k)||dis(x,q)+dis(y,q)==dis(x,y))
            printf("Y
");
        else printf("N
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/sanjinliushi/p/11704818.html