LCA最近公共祖先---倍增法笔记

最后都变了- 提交于 2019-11-26 12:29:12

 

 

先展示把代码发过来,今日有空再更新

#pragma GCC optimize(2)

#include<bits/stdc++.h>

using namespace std;
const int N = 1000000;
long long bit[N];
int depth[N],f[N][30];
vector<int> G[N];
 
void init(){ //预先把2的多少次方计算出来 
    bit[0]=1;
    for(int i=1;i<=29;i++) bit[i]=bit[i-1]*2;
}
void dfs(int u,int par){ //u:当前节点 par:u的父亲节点 
    depth[u]=depth[par]+1;
    f[u][0]=par;
    for(int i=1;i<=29;i++) f[u][i]=f[f[u][i-1]][i-1]; //计算u的各次方的祖先 
    for(int i=0;i<(int)G[u].size();i++){ //继续去遍历该节点的孩子节点 
        int v=G[u][i]; 
        if(v==par) continue;//因为是用邻接表存的,所以需要跳过父亲节点 
        dfs(v,u);
    }
}
int lca(int a,int b){
    if(depth[a]<depth[b]) swap(a,b); //保证深度大的在前,小的在后 
    int dif=depth[a]-depth[b]; //深度差 
    for(int i=29;i>=0;i--){
        if(bit[i] <= dif){ //在不超出深度差的范围向上爬 
            a=f[a][i]; //爬到的位置 
            dif -= bit[i]; //深度差更新 
        }
    }
    //此时a,b已经是相同的深度 
    if(a==b) return a; //如果a,b节点已经相同,所以a,b所在的节点就是lca 
     
    for(int i=29;i>=0;i--){
        if(bit[i]<=depth[a] && f[a][i]!=f[b][i]){ //bit[i]<=depth[a]:表示不跳出树之外 
            a=f[a][i];b=f[b][i];
        }
    }
    return f[a][0];//返回lca的儿子的父亲,也就是lca 
}

int main(){
    init();
    int n,m,s;
    scanf("%d %d %d",&n,&m,&s);
    int u,v;
    for(int i=1;i<=n-1;i++){
        scanf("%d %d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(s,0);
    while(m--){
        scanf("%d %d",&u,&v);
        printf("%d\n",lca(u,v));
    }
    return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!