#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
int n,m,s;
vector<int> edge[500005];
int depth[500005];
int anc[500005][20];
void dfs(int now, int fa){
depth[now]=depth[fa]+1;
anc[now][0] = fa;
for(int i=1;(1<<i)<=depth[now]-1;i++){
anc[now][i] = anc[anc[now][i-1]][i-1];
}
for(int i=0;i<(int)edge[now].size();i++){
int nxt = edge[now][i];
if(nxt==fa) continue;
dfs(nxt, now);
}
}
int lca(int x, int y){
if(depth[x]<depth[y]) swap(x,y);
if(depth[x]!=depth[y]){
for(int i=20;i>=0;i--){
if((1<<i)<=depth[x]-depth[y]){
x = anc[x][i];
}
}
}
if(x==y) return x;
for(int i=20;i>=0;i--){
if((1<<i)>depth[x]-1) continue;
if(anc[x][i]==anc[y][i]) continue;
x = anc[x][i];
y = anc[y][i];
}
return anc[x][0];
}
int main()
{
scanf("%d%d%d",&n,&m,&s); //n个点,m条边,s是根节点
for(int i=1;i<=n-1;i++){
int x,y;scanf("%d%d",&x,&y);
edge[x].push_back(y);
edge[y].push_back(x);
}
dfs(s,0); // 预处理每个节点的深度和第2^i级祖先
for(int i=1;i<=m;i++){
int x,y;scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y)); // 倍增法计算两个节点的最近公共祖先
}
return 0;
}
referência:
Resumo de alguns pontos sobre o algoritmo LCA (método de multiplicação) - Object_S Blog - CSDN Blog