https://www.luogu.org/problem/P3379
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e6 + 7;
int head[maxn],to[maxn],nex[maxn],d[maxn],fa[maxn][20];//fa[i][j]代表i點的第2^j個祖先
int tot;
void add(int x,int y)
{
to[++tot] = y;
nex[tot] = head[x];
head[x] = tot;
}
void dfs(int x)
{
for(int i = head[x];i;i = nex[i])
{
int v = to[i];
if(!d[v])
{
d[v] = d[x] + 1;
fa[v][0] = x;
dfs(v);
}
}
}
int lca(int x,int y)
{
if(d[x] < d[y])swap(x,y);//保證x是最深的
for(int i = 19;i >= 0;i--)
{
if(d[fa[x][i]] >= d[y])
x = fa[x][i];//將x移到和y一樣的深度
}
if(x == y)//x移到y了,那說明x就是xy祖先
return x;
for(int i = 19;i >= 0;i--)
{
if(fa[x][i] != fa[y][i])
{
x = fa[x][i];
y = fa[y][i];//x,y一起上移
}
}
return fa[x][0];//此時x和y已經在同一個節點下了,返回x的父節點即可。
}
int main()
{
int n,m,s;scanf("%d%d%d",&n,&m,&s);
for(int i = 1;i < n;i++)
{
int x,y;scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
d[s] = 1;fa[s][0] = 0;
dfs(s);
for(int i = 1;i <= 19;i++)
{
for(int j = 1;j <= n;j++)
{
fa[j][i] = fa[fa[j][i - 1]][i - 1];//j的2^i次方祖先等於j的2^i-1次方祖先的2^i-1次方祖先。
}
}
for(int i = 1;i <= m;i++)
{
int x,y;scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));
}
return 0;
}