LCA 倍增算法

LCA 倍增算法

时间复杂度为 O ( l o g N ) 的在线算法

D e p [ v ] 记录节点 v 的深度, F a [ v ] [ k ] 记录 v 向上第 2 k 个祖先的编号

代码

不带权

#include<iostream>
#include<cstdio>
#include<cmath>
#define ll long long
#define N 10050
using namespace std;
ll f[N][20],End[N],Next[N],Last[N],tot,Dep[N];
bool used[N];
void Ins(ll x,ll y){End[++tot]=y,Next[tot]=Last[x],Last[x]=tot;}
void DFS(ll x){
    Dep[x]=Dep[f[x][0]]+1;
    ll s=ceil(log2(Dep[x]));
    for(ll i=1;i<=s;i++)f[x][i]=f[f[x][i-1]][i-1];
    for(ll i=Last[x];i;i=Next[i])DFS(End[i]);
}
ll Find(ll x,ll y){//Dep[x]<Dep[y]
    if(Dep[x]>Dep[y])swap(x,y);
    ll d=Dep[y]-Dep[x],s=ceil(log2(Dep[y]));
    for(ll i=0;i<=s;i++)
        if(d&(1<<i))y=f[y][i];
    if(x==y)return x;
    for(ll i=s;i>=0;i--)
        if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    return f[x][0];
}
int main(){
    ll n,m;scanf("%lld",&n);
    for(ll i=1;i<n;i++){
        ll x,y;scanf("%lld%lld",&x,&y);
        used[y]=true,f[y][0]=x,Ins(x,y);
    }
    for(ll i=1;i<=n;i++)
        if(!used[i]){DFS(i);break;}//以i为根 建树+预处理
    scanf("%lld",&m);
    for(ll i=1;i<=m;i++){
        ll a,b;scanf("%lld%lld",&a,&b);
        printf("%lld\n",Find(a,b));
    }
    return 0;
}

带权

#include<iostream>
#include<cstdio>
#include<cmath>
#define N 4000
using namespace std;
int End[N],Len[N],Next[N],Last[N],dis[N][N],f[N][N],D[N],tot;
bool used[N];
void Ins(int x,int y,int len){
    End[++tot]=y;
    Len[tot]=len;
    Next[tot]=Last[x];
    Last[x]=tot;
}
void DFS(int fa){
    used[fa]=true;
    D[fa]=D[f[fa][0]]+1;
    int s=ceil(log2(D[fa]));
    for(int i=1;i<=s;i++){
        f[fa][i]=f[f[fa][i-1]][i-1];
        dis[fa][i]=dis[f[fa][i-1]][i-1]+dis[fa][i-1];
    }
    for(int i=Last[fa];i;i=Next[i])
        if(!used[End[i]]){
            f[End[i]][0]=fa,dis[End[i]][0]=Len[i];
            DFS(End[i]);
        }
}
int Find(int x,int y){//D[x]>D[y]
    int ans=0;
    if(D[x]<D[y])swap(x,y);
    int d=D[x]-D[y],s=ceil(log2(D[x]));
    for(int i=0;i<=s;i++)
        if(d&(1<<i))ans+=dis[x][i],x=f[x][i];
    if(x==y)return ans;
    for(int i=s;i>=0;i--)
        if(f[x][i]!=f[y][i]){
            ans+=dis[x][i]+dis[y][i];
            x=f[x][i],y=f[y][i];
        }
    return ans+dis[x][0]+dis[y][0];
}
int main(){
    int n,q;scanf("%d%d",&n,&q);
    for(int i=1;i<n;i++){
        int a,b,l;scanf("%d%d%d",&a,&b,&l);
        f[b][0]=a,dis[b][0]=l;
        Ins(a,b,l),Ins(b,a,l);
    }
    DFS(1);

    for(int i=1;i<=q;i++){
        int x,y;scanf("%d%d",&x,&y);
        printf("%d\n",Find(x,y));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/arliastark/article/details/80643374