YunYan

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

https://www.luogu.org/problemnew/solution/P3379

LCA叫做最短公共祖先,用来求距离树上两个节点最近的公共点;

常用倍增算法:

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int N=1E6+7;
long long bits[30];
int depth[N],fa[N][30];
vector<int >ve[N];
//"---------预处理部分---------"
void inint(){
    bits[0]=1;
    for(int i=1;i<30;i++) bits[i]=bits[i-1]<<1;//用一个数组记录2的i次幂,每次向上爬满足条件的2的最大i次幂 
}
void dfs(int x,int y){//x为子节点,y为父节点 
    depth[x]=depth[y]+1;//子节点与父节点的关系 
    fa[x][0]=y;
    //"----核心之一 --"
    for(int i=1;i<30;i++)    fa[x][i]=fa[fa[x][i-1]][i-1]; 
    //"-------"每次向上爬2的i次幂相当于先爬2的i-1次幂,在爬2的i-1次幂 
    for(int i=0;i<ve[x].size();i++){//临接表存图与x相联的点出了子节点就是父节点。将父节点排除掉 
        int x1=ve[x][i];
        if(x1!=y){
            dfs(x1,x);//让x做父节点,x1做子节点 
        }
    }
}
//"-----------------------------------" 
int lca(int x,int y){//我们规定x为较深的点,y为较浅的一个点 
    if(depth[x]<depth[y]) swap(x,y);//如果说depth[x]小的话,,要交换一下; 
    int dif=depth[x]-depth[y]; 
    for(int i=29;i>=0;i--){
        if(dif>=bits[i]){//将X和y变成同一高度。因就相当于将dif用二进制划分,然后记录一下x此时的位置 
            x=fa[x][i];
            dif=dif-bits[i];
        }
    }
    if(x==y) return x;//如果二者相等了说明二者在树枝的同一侧,y就是x的最近的根 
    for(int i=29;i>=0;i--){
        if(depth[x]>=bits[i]&&fa[x][i]!=fa[y][i]){//找到x和y的根的第一子节点 
            x=fa[x][i];
            y=fa[y][i];
        }
    }
    return fa[x][0];//返回自已子节点的父节点,就是公共根了 
}

int main(){
    inint();
    int n,m,s;
    scanf("%d%d%d",&n,&m,&s);
    int x,y;
    for(int i=1;i<=n-1;i++){
        scanf("%d%d",&x,&y);
        ve[x].push_back(y);
        ve[y].push_back(x);
    }
    dfs(s,0);//在这里s是总的根节点,我们规定如果越界,记为0,比如s的父节点就越界了,记录为0; 
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        printf("%d\n",lca(x,y));
    }
    return 0;
}

 

posted on 2019-08-08 16:46  Target--fly  阅读(299)  评论(0编辑  收藏  举报