最近公共祖先(LCA)

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 
 5 const int MAXN=500010;
 6 
 7 int n,m,s;
 8 int fa[MAXN][20];   //结点i往上2^j的祖先
 9 int dep[MAXN];   //每个结点的深度
10 
11 struct Edge
12 {
13     int next,to;
14 }e[MAXN*2];
15 int head[MAXN],cnt=0;
16 void addEdge(int x,int y)
17 {
18     cnt++;
19     e[cnt].next=head[x];
20     e[cnt].to=y;
21     head[x]=cnt;
22     return;
23 }
24 
25 void dfs(int u,int f)
26 {
27     fa[u][0]=f;
28     dep[u]=dep[f]+1;
29     for (int i=1;(1<<i)<=dep[u];i++)
30     {
31         fa[u][i]=fa[fa[u][i-1]][i-1];   //倍增求祖先
32     }
33     for (int i=head[u];i!=0;i=e[i].next)
34     {
35         int v=e[i].to;
36         if (v!=f) dfs(v,u);   //因双向建边,注意判断v是否为fa,否则会死循环
37     }
38     return;
39 }
40 
41 int lca(int x,int y)
42 {
43     if (dep[x]<dep[y]) swap(x,y);   //保证开始时 x深度>y
44     for (int i=19;i>=0;i--)
45     {
46         if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];   //将x上升到与y同一深度
47     }
48     if (x==y) return x;   //特判,y是x的祖先
49     for (int i=19;i>=0;i--)
50     {
51         if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];   //将x y上升到最近公共祖先的深度+1处,即最远的非公共祖先处
52     }
53     return fa[x][0];   //此时,最近公共祖先为当前结点的父结点
54 }
55 
56 int main()
57 {
58     scanf("%d%d%d",&n,&m,&s);
59     for (int i=1;i<n;i++)
60     {
61         int u,v;
62         scanf("%d%d",&u,&v);
63         addEdge(u,v);
64         addEdge(v,u);
65     }
66 
67     dfs(s,0);
68 
69     while (m--)
70     {
71         int x,y;
72         scanf("%d%d",&x,&y);
73         printf("%d\n",lca(x,y));   //求最近公共祖先
74     }
75 
76     return 0;
77 }

 

posted @ 2021-12-04 21:08  Hell0er  阅读(35)  评论(0编辑  收藏  举报