zoukankan      html  css  js  c++  java
  • 最近公共祖先

    洛谷P3379 【模板】最近公共祖先(LCA)

    题目描述

    如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

    输入输出格式

    输入格式:

    第一行包含三个正整数(N)(M)(S),分别表示树的结点个数、询问的个数和树根结点的序号。

    接下来(N-1)行每行包含两个正整数(x)(y),表示(x)结点和(y)结点之间有一条直接连接的边(数据保证可以构成树)。

    接下来(M)行每行包含两个正整数(a)(b),表示询问(a)结点和(b)结点的最近公共祖先。

    输出格式:

    输出包含(M)行,每行包含一个正整数,依次为每一个询问的结果。

    说明

    时空限制:1000ms,128M

    数据规模:

    对于30%的数据:N<=10,M<=10

    对于70%的数据:N<=10000,M<=10000

    对于100%的数据:N<=500000,M<=500000


    今天(2018.6.6)刚学离线的tarjan做法,复杂度近似为(O(n))

    主要思想:利用(dfs)的遍历顺序,来实时更新每个时间点某个点的祖先。

    我们在遍历到某个节点(i)时将这个节点标记已经访问,在 回溯到它父亲时 更新它的祖先(注意时间顺序)。当((i,j))是某个询问时,若(j)还未访问,则不执行操作;若(j)已经访问,此时(j)的祖先即为((i,j))的最近公共祖先。

    对于为什么,自己手动模拟一下其实不难明白。

    对于祖先关系,我们用并查集维护即可。


    code:

    #include <cstdio>
    const int N=500010;
    int n,m,s;
    struct Edge
    {
        int to,next;
    }g[N*2],edge[N*2];
    int head1[N],head2[N],cnt1=0,cnt2=0;
    void add1(int u,int v)
    {
        g[++cnt1].to=v;g[cnt1].next=head1[u];head1[u]=cnt1;
    }
    void add2(int u,int v)
    {
        edge[++cnt2].to=v;edge[cnt2].next=head2[u];head2[u]=cnt2;
    }
    int ans[N],used[N],f[N];
    int find(int x)
    {
        return f[x]=f[x]==x?x:find(f[x]);
    }
    void merge(int x,int y)//y±»ºÏ²¢
    {
        f[find(y)]=f[find(x)];
    }
    void tarjan(int now)
    {
        used[now]=1;
        for(int i=head1[now];i;i=g[i].next)
        {
            int v=g[i].to;
            if(!used[v])
            {
                used[v]=1;
                tarjan(v);
                merge(now,v);
            }
        }
        for(int i=head2[now];i;i=edge[i].next)
        {
            int v=edge[i].to;
            if(used[v])
                ans[i+1>>1]=find(v);
        }
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&s);
        int u,v;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            add1(u,v);add1(v,u);
        }
        for(int i=1;i<=n;i++)
            f[i]=i;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            add2(u,v);add2(v,u);
        }
        tarjan(s);
        for(int i=1;i<=m;i++)
            printf("%d
    ",ans[i]);
        return 0;
    }
    

    今天复习倍增的,贴一下代码

    #include <cstdio>
    #include <iostream>
    const int N=500010;
    int n,m,r;
    int head[N],to[N<<1],next[N<<1],cnt;
    void add(int u,int v)
    {
        to[++cnt]=v;next[cnt]=head[u];head[u]=cnt;
    }
    int f[N][21],dep[N];
    void dfs(int now,int fa)
    {
        for(int i=head[now];i;i=next[i])
        {
            int v=to[i];
            if(v!=fa)
            {
                f[v][0]=now;
                dep[v]=dep[now]+1;
                dfs(v,now);
            }
        }
    }
    int query(int x,int y)
    {
        if(dep[x]<dep[y]) std::swap(x,y);
        for(int i=20;i>=0;i--)
            if(dep[f[x][i]]>=dep[y])
                x=f[x][i];
        if(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];
    }
    void init()
    {
        for(int j=1;j<=20;j++)
            for(int i=1;i<=n;i++)
                f[i][j]=f[f[i][j-1]][j-1];
    }
    int main()
    {
        int u,v,a,b;
        scanf("%d%d%d",&n,&m,&r);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v),add(v,u);
        }
        dep[r]=1;
        dfs(r,0);
        init();
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&a,&b);
            printf("%d
    ",query(a,b));
        }
        return 0;
    }
    
    
  • 相关阅读:
    SharePoint 2013 安装.NET Framework 3.5 报错
    SharePoint 2016 配置工作流环境
    SharePoint 2016 站点注册工作流服务报错
    Work Management Service application in SharePoint 2016
    SharePoint 2016 安装 Cumulative Update for Service Bus 1.0 (KB2799752)报错
    SharePoint 2016 工作流报错“没有适用于此应用程序的地址”
    SharePoint 2016 工作流报错“未安装应用程序管理共享服务代理”
    SharePoint JavaScript API in application pages
    SharePoint 2016 每天预热脚本介绍
    SharePoint 无法删除搜索服务应用程序
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9145355.html
Copyright © 2011-2022 走看看