zoukankan      html  css  js  c++  java
  • 倍增求LCA

    倍增求LCA
    一,首先回顾一下什么是倍增算法,倍增算法就是改善一下一步一步跳的缓慢,改为跳2^k 步从而达到加快速度的目的,倍增算法一般要先预处理一个数组,代表从从某个点开始跳2^k 个数到达哪里,比如ST表的ST[i][j]代表从第i个数向后2^j 个数,树上倍增求LCA的f[i][j]表示i的第2^j 个祖先是谁。

    二,最近公共祖先LCA概念篇
    1,祖先:与x处于同一条重链且深度小于点x的节点都成为点想的祖先。
    2,公共祖先:若给定一棵树,结点z即是结点x的祖先,结点z也是结点y的祖先,那么称z是结点x和y的公共祖先。
    3,最近公共祖先:结点x和结点y的所有祖先中深度最深的那个,记作LCA(x,y)。

    比如在此图中,5的祖先有1和2; 5和6的公共祖先有1和2; 5和6的最近公共祖先是2; 有没有发现根节点是所有任意两个节点的公共祖先,

    所以最近公共祖先一定存在,最差是根节点。

    三,如何求解LCA
    1,考虑如何暴力求解,如果两个结点的深度相同,我们是不是只需要让两个结点同时一步一步往上走,即a走到它的父亲的同时,b也走到它的父亲,如果两个点走到的结点不相同就证明当前节点不是a和b的最近公共祖先就继续走,知道走到节点相同证明当前节点是点a和点b的最近公共祖先。
    2,考虑如何优化1,1缓慢的原因是它在一步一步的向上走所以导致了算法的低效,如果我们可以大步向上走,每次在不超过范围的情况下向上走2^k步再判断是不是就加快了算法速度,为了实现这个效果我们引入倍增算法
    首先要预处理两个数组Log(以2为底的对数中整数最大的那个),Log[0]=-1,Log[i]=Log[i>>1]|1;F(i, j) 表示点i 向上走2j 步的结点,Fi,0 就是点i 的父亲节点,F(i, j)= F((Fi, j−1), j−1)(从第i个点向上走2^j 个点肯定等于从i出发向上走2^(j-1) 个点再向上走2^(j-1)个节点。

    算法流程:
    将a 和b 调整到相同高度
    a. 判断a 和b 是否重合,若重合则该点即为答案
    b.令a 和b 一起向上移动尽可能大的距离,保证移动后两点不重合
    c. 此时两点的父亲结点即为答案

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define maxn 500005
     6 
     7 using namespace std;
     8 
     9 struct node
    10 {
    11     int ed,nxt;
    12 };
    13 node edge[maxn<<1];
    14 int first[maxn],n,m,s,cnt,f[maxn][30],Log[maxn],dep[maxn]; 
    15 
    16 inline void add_edge(int s,int e)
    17 {
    18     cnt++;
    19     edge[cnt].ed=e;
    20     edge[cnt].nxt=first[s];
    21     first[s]=cnt;
    22     return;
    23 }
    24 
    25 inline void deal_first(int k,int fa)
    26 {
    27     dep[k]=dep[fa]+1;
    28     f[k][0]=fa;
    29     for(int i=1;(1<<i)<=dep[k];i++)
    30         f[k][i]=f[f[k][i-1]][i-1];
    31     for(int i=first[k];i;i=edge[i].nxt)
    32     {
    33         int e=edge[i].ed;
    34         if(e==fa) continue;
    35         deal_first(e,k);
    36     }
    37 }
    38 
    39 inline int Lca(int a,int b)
    40 {
    41     if(dep[a]<dep[b]) swap(a,b);
    42     for(int i=Log[dep[a]];i>=0;i--)
    43         if(dep[f[a][i]]>=dep[b]) a=f[a][i];
    44     if(a==b) return a;
    45     for(int k=Log[dep[a]];k>=0;k--)
    46         if(f[a][k]!=f[b][k])
    47            a=f[a][k],b=f[b][k];
    48     return f[a][0];
    49 }
    50 
    51 int main()
    52 {
    53     scanf("%d%d%d",&n,&m,&s);
    54     for(int i=1;i<=n-1;i++)
    55     {
    56         int s,e;
    57         scanf("%d%d",&s,&e);
    58         add_edge(s,e);
    59         add_edge(e,s);
    60     }
    61     dep[s]=1;
    62     deal_first(s,0);
    63     Log[0]=-1;
    64     for(int i=1;i<=n;i++)
    65         Log[i]=Log[i>>1]+1;
    66     for(int i=1;i<=m;i++)
    67     {
    68         int a,b;
    69         scanf("%d%d",&a,&b);
    70         printf("%d
    ",Lca(a,b));
    71     }
    72     return 0;
    73 }
  • 相关阅读:
    2013.4.15 Particle Swarm Optimization with Skyline Operator for Fast Cloudbased Web Service Composition
    Adaptive service composition in flexible processes
    2013.4.13 DomainSpecific Service Selection for Composite Services
    2013.4.14 Modeling and Algorithms for QoSAware Service Composition in VirtualizationBased Cloud Computing
    2013.5.29 Towards Networkaware Service Composition in the Cloud
    Efficient algorithms for Web services selection with endtoend QoS constraints
    SQL Server中常用的SQL语句
    接口限流自定义注解
    linux服务器生产环境搭建
    MVEL自定义函数重复掉用报错:duplicate function
  • 原文地址:https://www.cnblogs.com/Hoyoak/p/11408639.html
Copyright © 2011-2022 走看看