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

 先暂时把模板写出来,A几道题再来补充

此模板也是洛谷上的一道模板题

P3379 【模板】最近公共祖先(LCA)

#pragma GCC optimize(2) //o2优化
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int L = 30;//2的指数的大小 
const int NN = 1e6+10;
int N,M,S;

ll bit[L];
int depth[NN];//depth[i]:节点i在树上的深度 
int fa[NN][L]; //fa[i][j]:节点i向上走2^j次方的节点 
vector<int> G[NN];//存图 


void init_log(){//预先把2的多少次方计算出来 
    bit[0] = 1;
    for(int i = 1;i<L;i++)
        bit[i] = bit[i-1]*2;
}

void DFS(int u,int par){//u:当前节点 par:u的父亲节点 
    depth[u] = depth[par]+1;
    fa[u][0] = par;
    for(int i = 1;i<L;i++){
        fa[u][i] = fa[fa[u][i-1]][i-1];//计算u的各次方的祖先 
    }
    for(auto v: G[u]){//继续去遍历该节点的孩子节点 
        if(v!=par){//因为是用邻接表存的,所以需要跳过父亲节点 
            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 = L-1;i>=0;i--){
        if(bit[i] <= dif){//在不超出深度差的范围向上爬 
            a = fa[a][i];//爬到的位置 
            dif -= bit[i];//深度差更新 
        }
    }
    //此时a,b已经是相同的深度
    if(a == b) return a; //如果a,b节点已经相同,所以a,b所在的节点就是lca 
    
    for(int i = L-1;i>=0;i--){
        if(bit[i] <= depth[a] && fa[a][i] != fa[b][i]){ //bit[i]<=depth[a]:表示不跳出树之外 
            a = fa[a][i];
            b = fa[b][i];
        }
    }
    return fa[a][0]; //返回lca的儿子的父亲,也就是lca 
}


int main(){
//    freopen("test.in","r",stdin);
    init_log();
    cin>>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);
    int a,b;
    for(int i = 1;i<=M;i++){
        scanf("%d%d",&a,&b);
        int lca = LCA(a,b);
        printf("%d\n",lca);
    }
    
    
    return 0;
}
原文地址:https://www.cnblogs.com/bigbrox/p/11320187.html