首页 > 代码库 > LCA 倍增

LCA 倍增

最近公共祖先

对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度尽可能大。

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int n,q;
 7 int cnt,head[500],r[500],deep[500],p[500][10];
 8 struct node{
 9     int v;
10     int next;
11 }s[500];
12 
13 void add(int u,int v){
14     s[++cnt].v=v;
15     s[cnt].next=head[u];
16     head[u]=cnt;
17 }
18 
19 void DFS(int x){//预处理深度 
20     for(int i=head[x];i;i=s[i].next){
21         int V=s[i].v;
22         if(!deep[V]){
23             deep[V]=deep[x]+1;
24             p[V][0]=x;
25             DFS(V);
26         }
27     }
28 }
29 
30 void init(){//p[i][j]表示i的第2^j的祖先 
31     for(int j=1;(1<<j)<=n;++j)
32         for(int i=1;i<=n;++i)
33             if(p[i][j-1]!=-1)
34                 p[i][j]=p[p[i][j-1]][j-1];//i的2^j的祖先-->i的2^(j-1)的祖先的2^(j-1)的祖先 
35 }
36 
37 int LCA(int a,int b){
38     if(deep[a]<deep[b])swap(a,b);
39     int i;
40     for(i=0;(1<<i)<=deep[a];++i); 
41     --i;
42     for(int j=i;j>=0;--j)//使a,b在相同深度
43         if(deep[a]-(1<<j)>=deep[b])a=p[a][j];
44     if(a==b)return a;
45     for(int j=i;j>=0;--j)//LCA 
46         if(p[a][j]!=-1&&p[a][j]!=p[b][j]){
47             a=p[a][j];
48             b=p[b][j];
49         }    
50     return p[a][0];
51 }
52 
53 int main(){
54     scanf("%d",&n);
55     for(int i=1;i<n;++i){
56         int x,y;
57         scanf("%d%d",&x,&y);
58         ++r[y];
59         add(x,y);
60     }
61     int rt;
62     for(int i=1;i<=n;++i)if(r[i]==0){rt=i;break;}
63     memset(p,-1,sizeof(p));
64     p[rt][0]=rt;
65     DFS(rt);
66     init();
67     
68     scanf("%d",&q);
69     for(int i=1;i<=q;++i){
70         int x,y;
71         scanf("%d%d",&x,&y);
72         printf("%d\n",LCA(x,y));
73     }
74     return 0;
75 }

 

LCA 倍增