• 【OI】倍增求LCA


    ╭(′▽`)╯

    总之,我们都知道lca是啥,不需要任何基础也能想出来怎么用最暴力的方法求LCA,也就是深度深的点先跳到深度浅的点的同一深度,然后一起向上一步步跳。这样显然太慢了!

    所以我们要用倍增,倍增比较屌,直接2^k速度往上跳,而且复杂度和树剖lca差不多,那么步骤分为两步

    1.让两个点到同一深度

    2.到了同一深度同步往上跳

    反正我一开始看的时候一直在想,万一跳过了怎么办?哈哈哈,所以说我们有办法嘛:

    定义deepv为v点的深度,设两个要求lca的点分别为a,b,且deepa >= deepb

    所以,枚举找出最大的k使2^k <= deepa,这就是最大的跳的距离;

    接着让他们到达同一深度:

    从大到小枚举k,如果 deepa - 2^k >= deepb就往上跳2^k步,因为如果跳了2^k步的话一定deepa >= deepb

    所以,我们跳的第一步一定是能跳的最大的一步,所以接下来只能跳次大的一步,同理跳完之后deepa >= deepb

    ......

    因为k是越来越小的,k = 0的时候2^k = 1,因此无论如何最后都会以最大的效率跳到相同的深度

    现在跳到了相同的深度,然后要同时向上走找到lca。

    假设跳了 2 ^ k步之后它们到的位置不相等,说明lca还在深度更浅的地方,因为如果跳之后到的位置相等了,显然这个位置一定在lca的上面

    所以,只要判断跳了 2 ^ k步后它们的位置如果不相等,就跳这步,这样就保证了跳到的深度一定小于lca,最后k = 0时 2 ^ k = 1,

    则枚举完了k,它们所在的深度显然一定是lca的深度-1,则lca就是它们任意一个的父亲。

    代码(luogu lca模板):

    #include <cstdio>
    #include <vector>
    #include <cstring>
    
    const int MaxN = 500010;
    
    int n,m,s;
    int par[MaxN][30];
    int deep[MaxN];
    bool vis[MaxN];
    
    struct Edge{
        int to,nxt;
    }e[MaxN*2];
    int head[MaxN];
    int cnt;
    
    void add(int u,int v){
        e[++cnt].to = v;
        e[cnt].nxt = head[u];
        head[u] = cnt;
    }
    
    void getdeep(int u){
        vis[u] = 1;
        for(int i = head[u]; i; i = e[i].nxt){
            
            int to = e[i].to;
            if(to == u || vis[to]) continue;
            
            par[to][0] = u;
            
            deep[to] = deep[u] + 1;
            
            getdeep(to);
            
        }
        
    }
    
    void getpar(){
        for(int up = 1; (1<<up) <= n; up++){
            for(int i = 1; i <= n ; i++){
                par[i][up] = par[par[i][up-1]][up-1];
            }
            
        }
        
    }
    
    
    int lca(int u,int v){
        if(deep[u] < deep[v] ) std::swap(u,v);
        
        int max_jump = -1;
        
        while(1<<(max_jump+1) <= deep[u]) max_jump++;
        
        for(int i = max_jump; i >= 0; i--){
            if(deep[u] - (1<<i) >= deep[v]){
                u = par[u][i];
            }
            
        }
        
        if(u == v)
            return u;
            
        for(int i = max_jump; i >= 0; i--){
            if(par[u][i] != par[v][i]){
                u = par[u][i];
                v = par[v][i];
                
            }
        }
        
        return par[u][0];
        
        
        
        return 0;
        
        
    } 
    
    
    
    int main()
    {
        scanf("%d%d%d",&n,&m,&s);
        
        for(int i = 1; i < n; i++ ){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
            //par[v][0] = u;
            //par[u][0] = v;
        }
    
        
        deep[s] = 0;
        
        getdeep(s);
        
        getpar();
        
        for(int i = 1; i <= m; i++){
            int a,b;
            scanf("%d%d",&a,&b);
            printf("%d
    ",lca(a,b));
            
        }
        
        //par[i][j] = par[par[i][j-1]][j-1]
        
            
        
        return 0;
    }
    View Code
  • 相关阅读:
    【神经网络与深度学习】Caffe Model Zoo许多训练好的caffemodel
    【计算机视觉】论文笔记:Ten years of pedestrian detection, what have we learned?
    【计算机视觉】论文笔记:Ten years of pedestrian detection, what have we learned?
    【计算机视觉】行人检测资源汇总
    【计算机视觉】行人检测资源汇总
    【神经网络与深度学习】卷积神经网络(CNN)
    【神经网络与深度学习】卷积神经网络(CNN)
    【CUDA开发】__syncthreads的理解
    【CUDA开发】__syncthreads的理解
    微信公众号-增加智能自动回复的功能--使用图灵机器人
  • 原文地址:https://www.cnblogs.com/dudujerry/p/11622916.html
Copyright © 2020-2023  润新知