f[i][j] 记录一个节点i的第j个的父节点 f[i][j] 不存在时 记为零
depth[i] 表示节点i 的深度
无向图 记录两个方向的边
重深度更深的节点开始寻找和另一个节点相同深度的节点
然后同时往上找父亲节点 此时的父亲节点就是最小公共祖先。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 1005;
int head[MAXN];
int depth[MAXN];
int f[MAXN][21];
int cnt=0;
struct node
{
int from, to;
} G[MAXN*2];
void add_edge(int u, int v)
{
G[cnt].from=head[u];
G[cnt].to=v;
head[u]=cnt++;
}
void dfs(int cur, int fa)
{
depth[cur]=depth[fa]+1;
for(int i=0; i<20; ++i)
{
f[cur][i+1]=f[f[cur][i]][i];
}
for(int i=head[cur]; ~i; i=G[i].from)
{
int v = G[i].to;
if (fa == v)
continue;
f[v][0]=cur;
dfs(v, cur);
}
}
int lca(int u, int v)
{
if(depth[u] < depth[v])
swap(u,v);
for(int i=20; i>=0; --i)
{
if(depth[f[u][i]]>=depth[v])
{
u=f[u][i];
}
if(u==v)
return u;
}
for(int i=20; i>=0; --i)
{
if(f[u][i]!=f[v][i])
{
u=f[u][i];
v=f[v][i];
}
}
return f[u][0];
}
int main()
{
int n, s, k;
int u, v;
scanf("%d %d %d", &n, &s, &k);
cnt=0;
memset(head, -1, sizeof(head));
for(int i=0; i<n-1; ++i)
{
scanf("%d %d", &u, &v);
add_edge(u,v);
add_edge(v,u);
}
dfs(s,0);
while(k--)
{
scanf("%d %d", &u, &v);
printf("%d\n", lca(u, v));
}
return 0;
}