To be continued…
LCA问题,即Lowest Common Ancestor 最近公共祖先
LCA问题有很多解法,比如
·暴力解法
分块解法
·倍增算法
·Tarjan算法
·LCT算法
在这里呢,我们只讨论倍增
倍增算法其实是一种类似于dp的实现
pa[i][j]
p
a
[
i
]
[
j
]
表示I号节点的
2j
2
j
个父亲
pa[i][j]=fa[i](j=0)
p
a
[
i
]
[
j
]
=
f
a
[
i
]
(
j
=
0
)
pa[i][j]=pa[pa[i][j−1]][j−1]](j>0)
p
a
[
i
]
[
j
]
=
p
a
[
p
a
[
i
]
[
j
−
1
]
]
[
j
−
1
]
]
(
j
>
0
)
查询的时候,我们将它们移至同一层次,再一起向上走即可
下面就直接上一道lca版题代码吧
题意:给出一棵树,和Q个询问,询问lca是谁
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int N=100105,M=200005,LOG=20;
struct node{
int v,nxt;
}edge[M];
int head[N],mcnt;
void add_edge(int u,int v){
mcnt++;
edge[mcnt].v=v;
edge[mcnt].nxt=head[u];
head[u]=mcnt;
}
int pa[N][LOG+1];
int deep[N];
int n,q;
void dfs(int u,int d){
deep[u]=d;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v;
if(v==pa[u][0])
continue ;
pa[v][0]=u;
dfs(v,d+1);
}
}
void pre(){
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i<=n;i++)
if(pa[i][j-1])
pa[i][j]=pa[pa[i][j-1]][j-1];
}
int lca(int x,int y){
if(deep[x]<deep[y])
swap(x,y);
int log=0;
int xx=deep[x];
while(xx)
xx>>=1,log++;
for(int i=LOG;i>=0;i--)
if(deep[x]-(1<<i)>=deep[y])
x=pa[x][i];
if(x==y)
return x;
for(int i=LOG;i>=0;i--)
if(pa[x][i]&&pa[x][i]!=pa[y][i])
x=pa[x][i],y=pa[y][i];
return pa[x][0];
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n-1;i++){
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
dfs(1,1);
pre();
int a,b;
for(int i=1;i<=q;i++){
scanf("%d%d",&a,&b);
printf("%d\n",lca(a,b));
}
}