倍增法找LCA(最短公共祖先)

题面来自牛客:https://ac.nowcoder.com/acm/problem/23482”

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+10;
int n,m,s,a,b;
vector<int> e[N];
int dep[N],fa[N][21];
int ans,ans1,ans2,ans3;
void dfs(int u,int father){
    dep[u]=dep[father]+1;
    fa[u][0]=father;
    for(int i=1;i<=20;i++)
        fa[u][i]=fa[fa[u][i-1]][i-1];
    for(auto v : e[u]){
        if(v!=father)dfs(v,u);
    }
}//处理 ST表,深度信息
int lca(int u,int v){
    if(dep[u]<dep[v])swap(u,v);//先让更深的点跳跃至与另一个点同深度
    for(int i=log2(dep[u]-dep[v]);i>=0;i--)
        if(dep[fa[u][i]]>=dep[v])
            u=fa[u][i];
//现在深度相同了

    if(u==v)return v;//此时两点可能在同一点,那么此点即为公共祖先

    for(int i=log2(dep[u]);i>=0;i--){
        if(fa[u][i]!=fa[v][i])
        {u=fa[u][i],v=fa[v][i];}//两点同时上跳
    }
    return fa[u][0];
}
int getdis(int x,int y){
    return dep[x]+dep[y]-2*dep[lca(x,y)];//通过lca获取两点的树上最短距离
}
int main(){
    int n;
    cin>>n;
    for(int i=0;i<n-1;i++){
        int u,v;
        cin>>u>>v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(1,0);//搜索处理ST表
    int u,v;
    cin>>u>>v;
    int q;
    cin>>q;
    for(int i=1;i<=q;i++){
        int x,y;
        cin>>x>>y;
        ans1=(getdis(x,y));
        ans2=(getdis(x,u)+getdis(v,y));
        ans3=(getdis(x,v)+getdis(u,y));
        cout<<min(ans1,min(ans2,ans3))<<endl;
    }
}
posted @ 2025-07-26 18:15  majikko  阅读(7)  评论(0)    收藏  举报