P3398 仓鼠找sugar(LCA)

Posted CCSU_Cola

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3398 仓鼠找sugar(LCA)相关的知识,希望对你有一定的参考价值。

题目链接

小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n。地下洞穴是一个树形结构。这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d)。他们都会走最短路径。现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友?

小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧!

题意:给出一棵树,给四个点a,b,c,d,问a-b的路径和c-d的路径有没有重合。

思路:若两个路径有重合那么一定有LCA(a,b)在c-d路径上或者LCA(c,d)在a-b路径上,先求出LCA(a,b)和LCA(c,d),然后如何判断一条路径上是否有这个点?若一个点a在x-y的路径上,那么一定有depth[a]>=depth[LCA(x,y)]且有LCA(a,x)==a或者LCA(a,y)==a,(depth表示该点在树上的深度)。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000100;
struct node{
    int x,to;
};
node e[maxn<<1];
int n,m,idx,h[maxn];
void add(int a,int b){
    e[idx].x=b,e[idx].to=h[a],h[a]=idx++;
}
int depth[maxn],fa[maxn][22];
void bfs(int root){
    memset(depth,0x3f,sizeof depth);
    depth[0]=0,depth[root]=1;
    queue<int>q;
    q.push(root);
    while(!q.empty()){
        int t=q.front();
        q.pop();
        for(int i=h[t];i!=-1;i=e[i].to){
            int j=e[i].x;
            if(depth[j]>depth[t]+1){
                depth[j]=depth[t]+1;
                q.push(j);
                fa[j][0]=t;
                for(int i=1;i<=20;i++){
                    fa[j][i]=fa[fa[j][i-1]][i-1];
                }
            }
        }
    }
}
int LCA(int a,int b){
    if(depth[a]<depth[b]){
        swap(a,b);
    }
    for(int k=20;k>=0;k--){
        if(depth[fa[a][k]]>=depth[b]){
            a=fa[a][k];
        }
    }
    if(a==b)return a;
    for(int k=20;k>=0;k--){
        if(fa[a][k]!=fa[b][k]){
            a=fa[a][k];
            b=fa[b][k];
        }
    }
    return fa[a][0];
}
int main(){
    memset(h,-1,sizeof h);
    scanf("%d%d",&n,&m);
    int a,b;
    for(int i=1;i<n;i++){
        scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
    }
    bfs(1);
    int c,d;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d%d",&a,&b,&c,&d);
        int aa=LCA(a,b);
        int bb=LCA(c,d);
        //cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
        //cout<<aa<<" "<<bb<<endl;
        if(depth[aa]>=depth[bb]){
            if(LCA(aa,c)==aa||LCA(aa,d)==aa){
                printf("Y\\n");
            }
            else printf("N\\n");
        }
        else{
            if(LCA(bb,a)==bb||LCA(bb,b)==bb){
                printf("Y\\n");
            }
            else printf("N\\n");
        }
    }
}

也可以采用树链剖分,将a-b路径的点置为1,然后查询c-d路径的最大值,如果大于0则说明有重合,否则没有重合,每次查询之后要将之前置为1的区间再置为0即可。

以上是关于P3398 仓鼠找sugar(LCA)的主要内容,如果未能解决你的问题,请参考以下文章

p3398 仓鼠找sugar (LCA+讨论)

P3398 仓鼠找sugar(LCA)

P3398 仓鼠找sugar(LCA)

洛谷lca+结论P3398 仓鼠找sugar

洛谷10月月赛Round.1| P3398 仓鼠找sugar[LCA]

P3398 仓鼠找sugar