美文网首页
LCA问题及其倍增解法

LCA问题及其倍增解法

作者: Chicago_01 | 来源:发表于2018-09-22 21:14 被阅读0次

    [TOC]

    LCA,最近公共祖先

    在有根树中,找出某两个结点u和v最近的公共祖先(或者说,离树根最远的公共祖先)。

    问题模型

    1 和 6 的 LCA 是 8 。
    11 和 1 的 LCA 是 8 。
    11 和 15 的 LCA 是 4 。
    14 和 13 的 LCA 是 1 。

    倍增

    • 核心思想:分治
    • 基本过程:
      1. 如果 a 和 b 深度不同,先把深度调浅,使他变得和浅的那个一样
      2. 现在已经保证了 a 和 b 的深度一样,所以我们只要把两个一起一步一步往上移动,直到他们到达同一个节点,也就是他们的最近公共祖先了。
    • 优化:我们记一个节点的父节点为他的 2^0 = 1 倍祖先,他的父节点的父节点为他的 2 倍祖先,依此类推。
    • 参考资料[ https://img.haomeiwen.com/i13783432/25111ed2a25eac1a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 ]

    #include <iostream>
    #include <cstring>
    #include <cstdio> 
    using namespace std;
    const int MAX_N=100000;
    const int MAX_M=1000000;
    int isleave[100050];
    struct edge{
        int v,next;
    }E[MAX_M];
    int p[MAX_N],eid;
    void init(){
        memset(p,-1,sizeof(p));
        memset(isleave,0,sizeof(isleave));
        eid=0;
    }
    void insert(int u,int v){
        E[eid].v=v;
        E[eid].next=p[u];
        p[u]=eid++;
    }
    int d[MAX_N],fa[MAX_N][20];
    void dfs(int u){
        for(int i=p[u];i!=-1;i=E[i].next){
            if(d[E[i].v]==-1){
                d[E[i].v]=d[u]+1;
                fa[E[i].v][0]=u;
                dfs(E[i].v);
            }
        }
    
    }
    
    int lca(int x,int y){
        int i,j;
        if(d[x]<d[y]){
            swap(x,y);
        }
        for(i=0;(1<<i)<=d[x];i++);
        i--;
        for(j=i;j>=0;j--){
            if(d[x]-(1<<j)>=d[y]){
                x=fa[x][j];
            }
        }
        if(x==y){
            return x;
        }
        for( j=i;j>=0;j--)
        {
            if(fa[x][j]!=fa[y][j]){
                x=fa[x][j];
                y=fa[y][j];
            }
        }
        return fa[x][0];
    }
    int main() {
        int n;
        init();
        cin>>n;
        for(int i=0;i<n-1;i++)
        {
            int u,v;
            cin>>u>>v;
            insert(u,v);
            insert(v,u);
            isleave[v]=1;
        }
        memset(d,-1,sizeof(d));
        int root;
        for(int i=1;i<=n;i++)
            {
            if(isleave[i]==0){
                root=i;
                break;
            }
        }
        d[root]=1;
        dfs(root);
        for(int level=1;(1<<level)<=n;level++){
            for(int i=1;i<=n;i++){
                fa[i][level]=fa[fa[i][level-1]][level-1];
            }
        }
        int q;
        cin>>q;
        while(q--){
            int a,b;
            cin>>a>>b;
            cout<<lca(a,b)<<endl;
        }
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:LCA问题及其倍增解法

          本文链接:https://www.haomeiwen.com/subject/rdbtoftx.html