题目链接
LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的 公共祖先 。 ———来自百度百科
学习视频:LCA算法讲解
利用倍增的思想从大往小跳,从小往大跳可能会有误判,跳2的整数次幂。
fa[i][j]表示i的2^j的祖先;
预处理:
把每一层的高度存在deap[i]中
核心语句fa[now][i]=fa[fa[now][i-1]][i-1];
now的2i的祖先==2i-1的2i-1的祖先
void dfs(int now, int fath) {
fa[now][0] = fath;
deap[now] = deap[fath]+1;
for(int i=1; i<=lg[deap[now]]; i++) {
fa[now][i]=fa[fa[now][i-1]][i-1];
}
for(int i=head[now]; i; i=e[i].to)
if(e[i].from != fath)
dfs(e[i].from,now);
}
倍增LCA
代码:
x=fa[x][lg[deap[x]-deap[y]]-1];
先跳到同一深度
然后一起往上跳,跳到LCA的下面
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5+100;
struct node {
int from,to;
} e[maxn<<1];
int head[maxn],tot=1;
int deap[maxn],fa[maxn][22],lg[maxn];
//fa[i][j]存的[i]向上走2的j次方的祖先;
void add(int x,int y) {
e[tot].from = y;
e[tot].to = head[x];
head[x] = tot++;
}
void dfs(int now, int father) {
fa[now][0] = father;
deap[now] = deap[father]+1;
for(int i=1; i<=lg[deap[now]]; i++) {
fa[now][i]=fa[fa[now][i-1]][i-1];
}
for(int i=head[now]; i; i=e[i].to)
if(e[i].from != father)
dfs(e[i].from,now);
}
int LCA(int x,int y) {
if(deap[x]<deap[y])
swap(x,y);
while(deap[x]>deap[y])
x=fa[x][lg[deap[x]-deap[y]]-1];
if(x==y) {
return x;
}
for(int k=lg[deap[x]]-1; k>=0; k--) {
if(fa[x][k] != fa[y][k]) {
x=fa[x][k],y=fa[y][k];
}
}
return fa[x][0];
}
int main() {
int n,m,s;
cin>>n>>m>>s;
for(int i=1; i<=n-1; i++) {
int x,y;
cin>>x>>y;
add(x,y);//无向图
add(y,x);
}
for(int i=1; i<=n; i++) {
lg[i] = lg[i-1]+(1<<lg[i-1]==i);
}
dfs(s,0);
for(int i=1; i<=m; i++) {
int x,y;
cin>>x>>y;
cout<<LCA(x,y)<<endl;
}
return 0;
}