#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N=1e6+10;//双向开两倍
int n,m,s;
int h[N],v[N],ne[N],idx;
void add(int x,int y){//领接表
v[++idx] = y;
ne[idx] = h[x];
h[x] = idx;
}
int f[N][20];
int d[N];
int x,y;
void init()//预处理: 求出每个节点的深度
{
//bfs
memset(d,0x7f,sizeof d);
d[0]=0;//对查询有用
queue <int >q;
d[s]=1;//根节点为第一层
q.push(s);
while(q.size()){
int t=q.front();
q.pop();
for(int i = h[t];i;i = ne[i]){
int j=v[i];
if(d[j] > d[t] + 1)//没有被更新
{
d[j] = d[t] + 1;
q.push(j);
f[j][0] = t;//往上一格是父亲
for (int k = 1; k <= 19; k++){//表示往上所有点都已经安置
f[j][k] = f[f[j][k-1]][k-1];
}
}
}
}
}
int query(int u, int v){
if(d[u]<d[v]) swap(u,v);//使一直调整u
//移动到同一层
for(int i = 19; i >= 0 ; i--){
if(d[f[u][i]] >= d[v]){//超过的 f为0 ,一直--
u = f[u][i];//小于的不断往上跳直到0
}
}
if(u == v) return u;//其中有一方是另一方的祖先节点
for(int i = 19; i >= 0; i--){
if(f[u][i] != f[v][i]){
u=f[u][i],v = f[v][i];//同时往上跳
}
}
return f[u][0];
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
//memset(h,-1,sizeof h);//idx是从0开始的
for(int i = 1; i < n; i++){
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
init();
// for(int i=1; i<= n ;i++){
// for(int j=0; j<= 19;j++)
// cout<<f[i][j]<<" ";
// cout<<endl;
//}
for(int i = 1; i <= m; i++){
scanf("%d%d",&x,&y);
printf("%d\n",query(x,y));
}
return 0;
}
P3379 【模板】最近公共祖先(LCA)
最新推荐文章于 2024-08-30 21:23:55 发布