LCA 倍增算法
时间复杂度为 的在线算法
记录节点 的深度, 记录 向上第 个祖先的编号
代码
不带权
#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;
}