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

      其实这个问题蒟蒻感觉,就是模拟,只不过,在模拟之前需要一些预处理。

      先谈谈倍增,其实就是对于寻找公共祖先,如果深度差距太大,就需要进行很多没有必要的计算:比如要跳4步,一步一步跳要4次,而我四步四步跳只要一次(当然有人人为我这么说太凑巧了,这里只是为了说明问题,并不是真实情况),那如果数据再大一点呢?倍增就显现出优势啦~。

      预处理:

      定义f[x][y]为从x->y需要跳2^y步,那么自然有f[x][y+1]=f [ f [ x ] [ y ] ] [ y ]。而且维护dep[]数组和f数组(f[v][0]=u)。

    void Deal_first(int u,int fa)
    {
        dep[u]=dep[fa]+1;
        for(int i=0; i<=19; i++)
            f[u][i+1]=f[f[u][i]][i];
        for(int j=head[u]; j; j=nxt[j])
        {
            int v=to[j];
            if(v==fa)
                continue;
            f[v][0]=u;
            Deal_first(v,u);
        }
    }

      利用链式前向星,一直搜下去,并维护dep(别忘了我们之后是要改变深度的啊)。

      LCA本体:(简单易懂,就不解释了)

    int LCA(int x,int y)
    {
        if(dep[x]<dep[y])
            swap(x,y);
        for(int i=20; i>=0; i--)
        {
            if(dep[f[x][i]]>=dep[y])
                x=f[x][i];
            if(x==y)//如果x,y在同一个分支上,直接返回就好
                return x;
        }
        for(int i=20; i>=0; i--)
        {
            if(f[x][i]!=f[y][i])
            {
                x=f[x][i];
                y=f[y][i];
            }
            
        }
        return f[x][0];
    }

      最后是完整代码:

    #include<cstdio>
    #include<iostream>
    using namespace std;
    #define maxn 500005
    int n,m,s;
    int to[2*maxn],head[2*maxn],nxt[2*maxn],cnt;
    int dep[maxn],f[maxn][21];
    void add(int a,int b)
    {
        cnt++;
        to[cnt]=b;
        nxt[cnt]=head[a];
        head[a]=cnt;
    }
    void Deal_first(int u,int fa)
    {
        dep[u]=dep[fa]+1;
        for(int i=0; i<=19; i++)
            f[u][i+1]=f[f[u][i]][i];
        for(int j=head[u]; j; j=nxt[j])
        {
            int v=to[j];
            if(v==fa)
                continue;
            f[v][0]=u;
            Deal_first(v,u);
        }
    }
    int LCA(int x,int y)
    {
        if(dep[x]<dep[y])
            swap(x,y);
        for(int i=20; i>=0; i--)
        {
            if(dep[f[x][i]]>=dep[y])
                x=f[x][i];
            if(x==y)//如果x,y在同一个分支上,直接返回就好
                return x;
        }
        for(int i=20; i>=0; i--)
        {
            if(f[x][i]!=f[y][i])
            {
                x=f[x][i];
                y=f[y][i];
            }
            
        }
        return f[x][0];
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&s);
        int a,b;
        for(int i=1; i<n; i++)
        {
            scanf("%d%d",&a,&b);
            add(a,b);
            add(b,a);
        }
        Deal_first(s,0);
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d",&a,&b);
            int ans=LCA(a,b);
            printf("%d
    ",ans);
        }
        return 0;
    }


      

  • 相关阅读:
    内存映射的原理
    Intel 面试(就不该报外企,英语是硬伤)
    基于多进程和基于多线程服务器的优缺点及nginx服务器的启动过程
    pdflush机制
    百度面试
    同步IO和异步IO的区别
    阿里面试
    linux内核学习之四:进程切换简述
    static成员函数不能调用non-static成员函数
    C/C++函数调用方式
  • 原文地址:https://www.cnblogs.com/popo-black-cat/p/10022339.html
Copyright © 2011-2022 走看看