注意!本篇题解不适合初学LCA的同学学习,因为我讲的很烂很不清楚。
倍增,顾名思义,就是成倍增加的意思。
我们知道,任何一个数字都可以表示成二进制。那么对于一条长度为n的链,我们总是可以跳大概logn次到达最后。
对于链上任意一点,我们都可以在大概logn的复杂度下询问到,其实倍增的思路就是二分,和快速幂一模一样。
那么怎么用倍增求LCA呢?
首先在树上求每个节点的深度,并且更新每个节点的祖先节点。假如有A和B两个结点,我们就假设深度大的为A,我们可以在logn的复杂度下跳到B的深度,然后A和B同时在logn的复杂度下跳到LCA。
所以倍增求LCA的复杂度是logn的啦。
下面上代码吧:(这是一份常数极大的模板,慎用。)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5+7;
const int maxl = 21;
int fa[maxn][maxl];
int depth[maxn];
int lg[maxn];
vector<int> G[maxn];
void dfs(int now,int last)
{
depth[now] = depth[last]+1;
fa[now][0] = last;
for(int i=1;(1<<i)<=depth[now];i++)
{
fa[now][i] = fa[fa[now][i-1]][i-1];
}
for(int i=0;i<G[now].size();i++)
{
if(G[now][i]!=last) dfs(G[now][i],now);
}
}
int lca(int x,int y)
{
if(depth[x]>depth[y]) swap(x,y);
while(depth[x]!=depth[y]) y = fa[y][lg[depth[y]-depth[x]]-1];
if(x==y) return x;
for(int k=lg[depth[y]];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;
scanf("%d%d%d",&n,&m,&s);
int x,y;
for(int i=0;i<n-1;i++)
{
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
for(int i=1;i<=n;i++)
{
lg[i] = lg[i-1]+(1<<lg[i-1]==i);
}
dfs(s,0);
for(int i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));
}
return 0;
}