洛谷P3398 仓鼠找sugar

裸的LCA。

对于每次询问,设a,b的LCA为A,c,d的LCA为B,分两种情况讨论:

1)A与B的深度相同,此时二人相遇的充要条件为A==B,即四个点的最近公共祖先相同。

2 ) A与B深度不同,设A的深度大于B的深度,若二人相遇,则c或d与A的LCA一定为A。

#include<cstdio>
#include<vector>
#define maxn 100005
inline int fread(void){
    char c;int num=0;
    while((c=getchar())==' '||c=='\r'||c=='\n');
    num+=c-'0';
    while((c=getchar())>='0'&&c<='9')
        num=num*10+c-'0';
    return num;
}
inline void swap(int &a,int &b){
    a^=b;b^=a;a^=b;
    return;
}
int n,q,fa[maxn][20],deep[maxn];
std::vector<int>sons[maxn];
inline void dfs(int u,int f,int dep){
    deep[u]=dep;fa[u][0]=f;
    int v,mx=sons[u].size();
    for(int i=0;i<mx;i++){
        v=sons[u][i];
        if(v!=f){
            dfs(v,u,dep+1);
        }
    }
    return;
}
inline int lca(int a,int b){
    if(deep[a]<deep[b])swap(a,b);//make deep[a]>deep[b]
    int i,j;
    for(i=0;(1<<i)<=deep[a];++i);
    --i;
    for(j=i;j>=0;--j)
        if(deep[a]-(1<<j)>=deep[b])
            a=fa[a][j];
    if(a==b)return a;
    for(j=i;j>=0;--j)
        if(fa[a][j]!=fa[b][j]&&fa[a][j]!=0)
            a=fa[a][j],b=fa[b][j];
    return fa[a][0];
}
int main(){
	//freopen("a.in","r",stdin); 
    int i,j,k,x,y,a,b,c,d;
    n=fread();q=fread();
    for(i=0;i<n-1;++i){
        x=fread();y=fread();
        sons[x].push_back(y);
        sons[y].push_back(x);
    }//Initialize
    dfs(1,0,0);
    for(j=1;(1<<j)<=n;++j)
        for(int i=1;i<=n;++i)
            if(fa[i][j-1]!=-1) 
                fa[i][j]=fa[fa[i][j-1]][j-1];
    //preprocess fathers
    while(q){
        a=fread();b=fread();
        c=fread();d=fread();
        int A=lca(a,b),B=lca(c,d);
        if(deep[A]==deep[B]){
            if(A==B)printf("Y\n");
            else printf("N\n");
            --q;continue;
        }//case 1
        if(deep[A]<deep[B]){
            swap(A,B);swap(a,c);swap(b,d);
        }//make deep[A]>deep[B]
        if(lca(c,A)==A) printf("Y\n");
        else if(lca(d,A)==A) printf("Y\n");
        else printf("N\n");//case 2
        --q;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值