【学习/模板】倍增求LCA

  

  P3379 【模板】最近公共祖先(LCA)

   走过路过不要错过!!

  一文让你秒懂倍增求LCA!!

  看完不会不要钱!!

  会了也不要!!

 1 #include<bits/stdc++.h>
 2 #define maxn 500001
 3 using namespace std;
 4 int log2n,n,m,s;
 5 struct node{
 6     int next,to;
 7 }e[maxn<<1];
 8 int num,head[maxn],deep[maxn],jump[maxn][23];
 9 //num 边的编号 head[i]以i节点为起点的边(存树时是最后一条边,遍历时从第一条边开始遍历)
10 // deep[i] 节点i的深度 jump[i][j] 当前节点为i,向上跳2^j步可以到达的节点位置 
11 void add(int from,int to)//建树 
12 {
13     e[++num].next=head[from];
14     e[num].to=to;
15     head[from]=num;
16 }
17 void dfs(int u)//通过深搜确定每个节点的深度 
18 {
19     for(int i=head[u];i;i=e[i].next)//邻接表遍历 
20     {
21         int v=e[i].to;//边i以节点u为起点以节点v为终点 
22         if(v!=jump[u][0])//如果v不是u的父节点 
23         {
24             jump[v][0]=u;//那么v的父节点是u 
25             deep[v]=deep[u]+1;//所以v的深度比u的深度大一 
26             dfs(v);//继续搜QAQ 
27         }
28     }
29 }
30 void bzinit()//预处理出每个节点向上走2^i步可以走到的节点位置 
31 {
32     for(int i=1;i<=log2n;i++)//2^log2n==n i<=log2n可以保证跳不出n个节点 
33     {
34         for(int j=1;j<=n;j++)
35         {
36             jump[j][i]=jump[jump[j][i-1]][i-1]; 
37             //2^i-1+2^i-1==2*2^i-1==2^i 故上式成立  
38         }
39     }
40 }
41 int lca(int x,int y)//求最近公共祖先 
42 {
43     if(deep[x]<deep[y]) swap(x,y);//保证x的深度永远大于y的深度 
44     int t=deep[x]-deep[y];//xy之间的高度差 
45     for(int i=0;(1<<i)<=n;i++)
46     //从0开始 因为2^0=1 一步是最小的运动单位(1<<i)<=n保证了跳不出n个节点  
47     {
48         if(t&(1<<i))//&运算符 只有1&1==1 其余均为零 
49         {
50             x=jump[x][i];
51             //当高度差在二进制下,该位不为零时跳,保证了可以使两个节点先跳到同一高度差 
52             /*任何一个正整数都能被表示为一些2的n次方加起来
53             十进制:16=16        15=8+4+2+1          10=8+2        5=4+1        
54             二进制:10000=10000  1111=1000+100+10+1  1010=1000+10  101=100+1    */
55         }
56     }
57     if(x==y) return x; 
58     for(int i=log2n;i>=0;i--)
59     //开始跳时先大步跳,后小步跳,避免错过lca 
60     {
61         if(jump[x][i]!=jump[y][i])
62         //当从xy节点跳2^i步不相等时,证明还未找到lca,不存在错过的情况,可以跳 
63         {
64             x=jump[x][i];
65             y=jump[y][i];
66         }
67     }
68     return jump[x][0];
69     //当跳至lca以上时,节点相同,为避免这种情况,跳到lca深度加一的点,然后返回该节点的父节点,即lca;
70 }
71 int main()
72 {
73     int x,y;
74     cin>>n>>m>>s;
75     log2n=log(n)/log(2)+1;
76     for(int i=1;i<n;i++)
77     {
78         scanf("%d%d",&x,&y);
79         add(x,y);
80         add(y,x);//建两边图,可以向下建树向上查找之类的 
81     }
82     deep[s]=1;
83     jump[s][0]=0;
84     dfs(s);
85     bzinit();
86     for(int i=1;i<=m;i++)
87     {
88         scanf("%d%d",&x,&y);
89         printf("%d
",lca(x,y));
90     }
91     return 0;    
92 }

这绝对是我写过有最详细注释的代码qwq

而且十分清晰易懂qwq

夸我!!

总之岁月漫长,然而值得期待。
原文地址:https://www.cnblogs.com/Hwjia/p/9515818.html