LCA
本
篇
博
客
讲
解
的
是
倍
增
求
L
C
A
的
方
法
本篇博客讲解的是倍增求LCA的方法
本篇博客讲解的是倍增求LCA的方法
对
于
一
颗
树
,
我
们
先
给
每
个
点
求
出
各
级
祖
先
对于一颗树,我们先给每个点求出各级祖先
对于一颗树,我们先给每个点求出各级祖先
void dfs(int ss,int fath){
depth[ss]=depth[fath]+1;
if(ss!=s)fa[ss][0]=fath;//赋初值
for(int i=1;i<=lg[depth[ss]];i++){
fa[ss][i]=fa[fa[ss][i-1]][i-1];//可以画一棵树看看,发现ss的第i-1级祖先的i-1级祖先即为ss的第i祭祖先
}
for(int i=head[ss];i;i=q[i].link){
int v=q[i].v;
if(v==fath) continue;
dfs(v,ss);
}
}
LCA的求法:
int Lca(int x,int y){
if(depth[x]<depth[y]) swap(x,y);
while(depth[x]>depth[y]){
x=fa[x][lg[depth[x]-depth[y]]];//即x最多只能跳2^log2(depth[x]-depth[y])级祖先,最多depth[x]-depth[y]步
}
if(x==y) return x;
for(int j=lg[depth[x]-1];j>=0;j--){
if(fa[x][j]!=fa[y][j]){
x=fa[x][j],y=fa[y][j];//因为x,y的深度相同,所以x,y到lca跳的距离应该是一样的,即一定存在fa[x][j]==fa[y][j],同理,往上跳了之后深度还是一样的,一直跳下去
}
}
return fa[x][0];
}
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int n,m,s,cnt=0,head[N];
struct edge{
int link,v;
}q[N<<1];
void put(int x,int y){
q[++cnt].v=y;
q[cnt].link=head[x];
head[x]=cnt;
}
int depth[N],lg[N],fa[N][20];
void dfs(int ss,int fath){
depth[ss]=depth[fath]+1;
if(ss!=s)fa[ss][0]=fath;
for(int i=1;i<=lg[depth[ss]];i++){
fa[ss][i]=fa[fa[ss][i-1]][i-1];
}
for(int i=head[ss];i;i=q[i].link){
int v=q[i].v;
if(v==fath) continue;
dfs(v,ss);
}
}
int Lca(int x,int y){
if(depth[x]<depth[y]) swap(x,y);
while(depth[x]>depth[y]){
x=fa[x][lg[depth[x]-depth[y]]];
}
if(x==y) return x;
for(int j=lg[depth[x]-1];j>=0;j--){
if(fa[x][j]!=fa[y][j]){
x=fa[x][j],y=fa[y][j];
}
}
return fa[x][0];
}
int main(){
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
put(u,v),put(v,u);
}
lg[1]=0;
for(int i=2;i<=n;i++){
lg[i]=lg[i>>1]+1;
}
dfs(s,0);
while(m--){
int u,v;
scanf("%d%d",&u,&v);
int lca=Lca(u,v);
printf("%d\n",lca);
}
}