zoukankan      html  css  js  c++  java
  • 数据结构——关于倍增LCA那点事

        关于LCA那点事~~

      首先我们要了解LCA为什么

      LCA所求是公共最近祖先

      听上去可能很玄学..............

      其大意即为给定一棵树,在上面选一些点,他们所有人的最近

    父亲.

      首先我们整理思路,思考一些可行的方案~~~~~

      1.蒟蒻:我会暴力!!

        找到点一步一步先把所有点提到同一个deep处,然后大家

    同步往上跳,直到大家重合.

      时间复杂度O(n*k);//k为查询次数

      died;

      2.小牛:我会RMQ,不会LCA!!

        同学你好好听课

      3.中牛:我会LCA!!

        同学哪种求法?? 中牛:暴力!!

      抬走下一位

      4.大牛:我会tarjan_LCA!!!

        说的好我不会.....

      抬走下一位

      5.又一只蒟蒻:我会倍增LCA

        if(倍增LCA[蒟蒻]==true) 蒟蒻=Zafkiel

      很好我们就来学习倍增LCA好了   qwq

        倍增LCA

      倍增LCA的基本思路很好,代码也不是很难,但是

    容易被卡常,但是对于一只非常蒻的蒟蒻来说已经是很好的算法了

      LCA的思想:倍增LCA的思想和RMQ的思想是非常接近的,基本思路

    就是我们用log优化向上跳时所跳的距离,使其不用一个一个的跳,这就

    使时间复杂度减了很多,变为O(logn),就很好;

      思路:首先建树,深搜求树上点的深度,然后写出LCA函数,即可

      看似简单....

      来道例题  

      [Ahoi2008]Meet 紧急集合

      题目描述太长了,我们简化一下

      给定一棵树,给定三个点,求三个点的LCA和三个点到

    目标点所需步数.

      思路:三个点两两求LCA,最后差分计算步数即可

      
     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 long long ans;
     4 int dis[500010][25],lg[500010],deep[500010],t;
     5 struct node{
     6     int to;
     7     int nxt;
     8 }edge[1000010];
     9 int head[1000010],cnt;
    10 inline void add(int from,int to){
    11     cnt++;
    12     edge[cnt].to=to;
    13     edge[cnt].nxt=head[from];
    14     head[from]=cnt;
    15 }
    16 inline int lca(int x,int y){
    17     if(deep[x]<deep[y]) swap(x,y);//假设x深度大于y
    18     while(deep[x]>deep[y]) x=dis[x][lg[deep[x]-deep[y]]-1];//x,y调整到同一深度    
    19     if(x==y) return x;//深度相同则直接返回 
    20     for(register int k=lg[deep[x]];k>=0;k--){//x,y一起向上跳
    21         if(dis[x][k]!=dis[y][k]){
    22             x=dis[x][k];
    23             y=dis[y][k];
    24         }
    25     }
    26     return dis[x][0];
    27 }
    28 void dfs(int x,int fa){
    29     deep[x]=deep[fa]+1;//处理深度
    30     dis[x][0]=fa;
    31     for(register int i=1;(1<<i)<=deep[x];i++) dis[x][i]=dis[dis[x][i-1]][i-1];
    32     for(register int i=head[x];i;i=edge[i].nxt) if(edge[i].to!=fa) dfs(edge[i].to,x);
    33 }
    34 int n,m;
    35 int a,b,c;
    36 int main(){
    37     scanf("%d%d",&n,&m);
    38     for(register int i=1;i<=n-1;i++){
    39         scanf("%d%d",&a,&b);
    40         add(a,b);
    41         add(b,a);
    42     }
    43     dfs(1,0);
    44     for(register int i=1;i<=n;i++) lg[i]=lg[i-1]+(1<<lg[i-1]==i);//常数优化 
    45     for(register int i=1;i<=m;i++){
    46         ans=0;
    47         scanf("%d%d%d",&a,&b,&c);
    48         int t1=lca(a,b);//三者分别求LCA
    49         int t2=lca(a,c);
    50         int t3=lca(b,c);
    51         if(t1==t2) t=t3;
    52         else if(t1==t3) t=t2;
    53         else if(t2==t3) t=t1;
    54         ans=deep[a]+deep[b]+deep[c]-deep[t1]-deep[t2]-deep[t3];//差分
    55         printf("%d %lld
    ",t,ans);
    56     }
    57     return 0;
    58 }
    [Ahoi2008]Meet 紧急集合

      总结一下:倍增LCA的用途其实比较单调,因为会各种被卡

    但是我等蒟蒻别无他法(tarjan老贼出来挨打),所以这个算法会贯穿

    我们整个树上问题,学会他是很必要的(当然大佬们可能已经学会了LCA的四种求法,那就当我没说qwq)

      end;

  • 相关阅读:
    windowswindows/windowslinux间文件远程传输
    GNUstep ObjectC Ubuntu
    Linux日常问题处理集
    上网实用技巧
    ubuntu host VirtualBox xp guest networking
    平衡组/递归匹配
    Linux在线词典
    正则表达式的构造摘要
    Microsoft .NET Pet Shop 4 架构与技术分析
    ASP.net 2.0资料吐血收藏(^_^) (转)
  • 原文地址:https://www.cnblogs.com/liuhailin/p/11268690.html
Copyright © 2011-2022 走看看