#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 500000 + 5;
// n 边数 m 所求的 2 个节点 s 根节点
int n,m,s;
//用于存图
vector <int> mapp[N];
// fa 倍增数组(fa[i][j]=fa[fa[i][j-1]][j-1]) dep 存储节点深度
int fa[N][N],dep[N];
//dfs 处理树状数组
//now 当前结点 father 父亲节点
void dfs(int now,int father)
{
//当前结点的深度为其父节点的深度 +1
dep[now]=dep[father]+1;
//当前结点的上一个为父节点
fa[now][0]=father;
//遍历当前结点向上跳2^1~2^20步所对应的点
//dfs 核心内容:
for(int k=1;k<=20;k++)
{
//计算当前节点向上跳2^k步对应的点
fa[now][k]=fa[fa[now][k-1]][k-1];
}
//遍历所有的以当前节点为父节点的子节点
for(int i=0;i<mapp[now].size();i++)
{
//记录下一个子节点
int next=mapp[now][i];
//由于存储为双向边 所以遍历到父节点的时候跳过
if(next==father) continue;
//如果下一个不是子节点 则从该子节点开始遍历
if(next!=father) dfs(next,now);
}
}
//lca 计算两点的最近公共祖先
//a b 为两个点
int lca(int a,int b)
{
//为了便于计算 用深度较大的点进行同一深度运算
if(dep[a]<dep[b]) swap(a,b);
//统一深度 从2^20开始看可不可以向上跳
for(int i=20;i>=0;i--)
{
//如果深度较大的点向上跳 2^i 个点 大于或等于深度较小的点的深度
//则深度较大的点向上跳 2^i 个点
if(dep[fa[a][i]]>=dep[b]) a=fa[a][i];
//如果两点重合了 则深度较小的点为两点的LCA
if(a==b) return a;
}
//LCA核心思想:
//两点同时向上跳 如果跳到了同一个点 可能不是最近的公共祖先
//所以应该调到两点补充和的位置
for(int i=20;i>=0;i--)
{
//如果两点向上跳 2^i 个点不重合
if(fa[a][i]!=fa[b][i])
{
//则两点向上跳 2^i 个点
a=fa[a][i];
b=fa[b][i];
}
}
//最后返回其中一点的父节点 即为这两点的 LCA
return fa[a][0];
}
int main()
{
//输入边数 操作数 根节点编号
cin >> n >> m >> s;
//输入每条边所对应的 2 个节点的基本信息
for(int i=1;i<n;i++)
{
//两个节点
int x,y;
//输入两个节点
cin >> x >> y;
//由于要便利树状数组 所以要双向存边
mapp[x].push_back(y);
mapp[y].push_back(x);
}
//初始化树状数组
dfs(s,0);
//处理 lca
for(int i=1;i<=m;i++)
{
//a b 为 lca 所需的两个子节点
int a,b;
//输入两个子节点
cin >> a >> b;
//求出两点的 lca 并输出
cout << lca(a,b) << endl;
}
return 0;
}
"for(int i=0;i<mapp[now].size();i++)"这个有编译错误 过不了你谷评测机 但是本地运行没有问题