zoukankan      html  css  js  c++  java
  • 【学习/模板】倍增求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

    夸我!!

    总之岁月漫长,然而值得期待。
  • 相关阅读:
    Sizzle选择器引擎介绍
    from、includes、indexOf
    indexOf与includes的区别
    ES6 find 和 filter 的区别
    Spring MVC多个视图解析器及优先级
    Spring MVC多个视图解析器及优先级
    freemarker 中文乱码问题解决办法
    freemarker 中文乱码问题解决办法
    freemarker 中文乱码问题解决办法
    Spring集成MyBatis 通用Mapper以及 pagehelper分页插件
  • 原文地址:https://www.cnblogs.com/Hwjia/p/9515818.html
Copyright © 2011-2022 走看看