zoukankan      html  css  js  c++  java
  • [OI学习笔记]倍增LCA

    这也是洛谷P3379 【模板】最近公共祖先(LCA)的代码

    1.首先预处理upto[i][j]表示点i向上跳2j 个点到达的点,d[i]表示i的深度

    2.然后把两个被询问的点搬到同一深度,具体操作是:

      假设深的点为a,那么a每次把a迭代为 upto[a][log2(d[a]-d[b])] ,直到d[a]==d[b]

    3.将他们不断向上跳尽量大,使他们不重合,直到不能再在这个条件下向上跳

      具体操作是从大到小枚举k(最大 k=log2(深度) ,因为最多跳到root),然后a,b都向上跳2k 个点,直到不能再跳

    4.不能跳之后,那么ans就是他们的父亲了

    (p.s. 还可以实现预处理数组lg[i]=log2(i)+1以加快速度,具体实现看代码)

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int MAXN = 500001;
    
    inline int read(){
        int x=0,w=1;char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-')w=-1;
            c=getchar();
        }
        while(c>='0'&&c<='9'){
            x=(x<<3)+(x<<1)+c-'0';
            c=getchar();
        }
        return x*w;
    }
    
    int n,t,root;
    int upto[MAXN][25],d[MAXN]={0},first[MAXN],lg[MAXN];
    
    struct edge{
        int u,v,next;
    }e[2*MAXN];
    
    int tot=0;
    void insert(int u,int v){
        ++tot;e[tot].u=u;e[tot].v=v;e[tot].next=first[u];first[u]=tot;
    }
    
    void init(int u,int fa){
        d[u]=d[fa]+1;
        upto[u][0]=fa;
        for(int k=1;(1<<k)<=d[u];k++){
            upto[u][k]=upto[upto[u][k-1]][k-1];
        }
        for(int i=first[u];i!=-1;i=e[i].next){
            int v=e[i].v;
            if(v!=fa)init(v,u);
        }
    }
    
    int solve(int a,int b){
        if(d[a]<d[b])swap(a,b);
        while(d[a]>d[b]){
            a=upto[a][lg[d[a]-d[b]]-1]; 
        }
        if(a==b)return a;
        for(int k=lg[d[a]]-1;k>=0;k--)
            if(upto[a][k]!=upto[b][k]){
                a=upto[a][k];b=upto[b][k];
            }
        return upto[a][0];
    }
    
    int main(){
        memset(first,-1,sizeof(first)); 
        n=read();t=read();root=read();
        for(int i=1;i<n;i++){
            int x=read(),y=read();
            insert(x,y);
            insert(y,x);
        }
        init(root,0);
        for(int i=1;i<=n;i++)
            lg[i]=lg[i-1]+(1<<lg[i-1]==i);//预处理lg[i]=log2(i)+1 
        for(int i=1;i<=t;i++){
            int a=read(),b=read();
            printf("%d
    ",solve(a,b));
        }
        return 0;
    }
    本篇文章为SHINE_GEEK原创,转载请注明来源!
    written_by:SHINE_GEEK

    -------------------------------------
    签名:自己选的路,跪着也要走完;理想的实现,需要不懈奋斗!
    -------------------------------------
  • 相关阅读:
    卡特兰数列(蒟蒻的学习笔记)
    10月7日 蒟蒻的流水账
    10月6日 蒟蒻的流水账
    10月5日 蒟蒻的流水账
    10月4号 蒟蒻的流水账
    2017 10 14(吐槽初赛)
    2017 10 13
    个人介绍
    luogu P1156 垃圾陷阱
    模板之矩阵快速幂(luogu P3390【模板】矩阵快速幂)
  • 原文地址:https://www.cnblogs.com/sjrb/p/10390627.html
Copyright © 2011-2022 走看看