https://www.cnblogs.com/lbssxz/p/11114819.html
1 #include<cstdio>
2 #include<iostream>
3 using namespace std;
4 const int maxn=1e5+10;
5 int n,m,s,num=0,head[maxn],dep[maxn],f[maxn][23];
6 int a1,a2;
7 struct edg{
8 int next,to;
9 }G[maxn];
10 void edge_add(int u,int v)//链式前向星存图
11 {
12 num++;
13 G[num].next=head[u];G[num].to=v;head[u]=num;
14 G[++num].next=head[v];G[num].to=u;head[v]=num;
15 }
16 void dfs(int u,int father)//对应深搜预处理f数组
17 {
18 dep[u]=dep[father]+1;
19 for(int i=1;(1<<i)<=dep[u];i++){
20 f[u][i]=f[f[u][i-1]][i-1];
21 }
22 for(int i=head[u];i;i=G[i].next){
23 int v=G[i].to;
24 if(v==father)continue;//双向图需要判断是不是父亲节点
25 f[v][0]=u;
26 dfs(v,u);
27 }
28 }
29 int lca(int x,int y)
30 {
31 if(dep[x]<dep[y]) swap(x,y);
32 for(int i=20;i>=0;i--)//从大到小枚举使x和y到了同一层
33 {
34 if(dep[f[x][i]]>=dep[y])
35 x=f[x][i];
36 if(x==y)return x;
37 }
38 for(int i=20;i>=0;i--)//从大到小枚举
39 {
40 if(f[x][i]!=f[y][i])//尽可能接近
41 {
42 x=f[x][i];y=f[y][i];
43 }
44 }
45 return f[x][0];//随便找一个**输出
46 }
47 int main(){
48 scanf("%d%d%d",&n,&m,&s);
49 for(int i=1;i<n;i++){
50 scanf("%d",&a1);
51 scanf("%d",&a2);
52 edge_add(a1,a2);//链式存边
53 }
54 dfs(s,0);
55 for(int i=1;i<=m;i++){
56 scanf("%d %d",&a1,&a2);
57 printf("%d\n",lca(a1,a2));//求两个节点的LCA
58 }
59 }
来源:https://www.cnblogs.com/pangbi/p/12485561.html