• lca 在线,离线 poj 1330


    题目链接:Nearest Common Ancestors

    思路:利用flag来标记儿子结点,最后只有根节点没有被标记,那么没有被标记的点也就是根节点被我们找到了

    在线做法:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <cmath>
    using namespace std;
    const int maxn=10000+10;
    const int M=20;
    struct node
    {
        int v,next;
    }e[maxn];
    int bit[M];
    int dp[maxn<<1][M],depth[maxn<<1],euler[maxn<<1],pos[maxn],head[maxn],vis[maxn],flag[maxn];
    int T,n,tot;
    void Swap(int &a,int &b)
    {
        int c;
        c=a;
        a=b;
        b=c;
    }
    void build(int u,int v)
    {
        e[T].v=v;
        e[T].next=head[u];
        head[u]=T++;
    }
    void init()
    {
        memset(vis,0,sizeof(vis));
        memset(head,-1,sizeof(head));
        memset(flag,0,sizeof(flag));
        T=0;
        tot=0;
        int u,v;
        for(int i=0;i<n-1;i++)
        {
            scanf("%d%d",&u,&v);
            build(u,v);
            flag[v]=1;
        }
    }
    void dfs(int u,int dep)
    {
        vis[u]=1;
        euler[++tot]=u;
        depth[tot]=dep;
        pos[u]=tot;
        for(int i=head[u];~i;i=e[i].next)
        {
            int v=e[i].v;
            if(!vis[v])
            {
                dfs(v,dep+1);
                euler[++tot]=u;
                depth[tot]=dep;
            }
        }
    }
    void ST(int len)
    {
        for(int i=1;i<=len;i++)
            dp[i][0]=i;
        int k=(int )(log(len*1.0)/log(2.0));
        for(int j=1;j<=k;j++)
        {
            for(int i=1;i+bit[j]<=len;i++)
            {
                int l=dp[i][j-1];
                int r=dp[i+bit[j-1]][j-1];
                dp[i][j]=depth[l]<depth[r]?l:r;
            }
        }
    }
    int  RMQ(int x,int y)
    {
        int len=y-x+1;
        int k=(int )(log(len*1.0)/log(2.0));
        int l=dp[x][k];
        int r=dp[y-bit[k]+1][k];
        return depth[l]<depth[r]?l:r;
    }
    void lca(int x,int y)
    {
        int l=pos[x];
        int r=pos[y];
        if(l>r)
            Swap(l,r);
        printf("%d
    ",euler[RMQ(l,r)]);
        return;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        for(int i=0;i<M;i++)
            bit[i]=1<<i;
        int kase;
        scanf("%d",&kase);
        while(kase--)
        {
            scanf("%d",&n);
            init();
            for(int i=1;i<=n;i++)
            {
                if(!flag[i])
                {
                    dfs(i,1);
                    break;
                }
            }
            ST(2*n-1);
            int ql,qr;
            scanf("%d%d",&ql,&qr);
            lca(ql,qr);
        }
        return 0;
    }

    离线做法:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include  <algorithm>
    #include <stack>
    #include <queue>
    #include <vector>
    
    using namespace std;
    const int maxn=10000+10;
    struct node
    {
        int v,next;
    }e[maxn<<1];
    int head[maxn],vis[maxn],fa[maxn],flag[maxn];
    int T,n;
    int ql,qr,q;
    void build(int u,int v)
    {
        e[T].v=v;
        e[T].next=head[u];
        head[u]=T++;
    }
    void init()
    {
        memset(head,-1,sizeof(head));
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
            fa[i]=i;
        memset(flag,0,sizeof(flag));
        T=0;
        q=0;
        int u,v;
        for(int i=0;i<n-1;i++)
        {
            scanf("%d%d",&u,&v);
            build(u,v);
            flag[v]=1;
            //build(v,u);
        }
        scanf("%d%d",&ql,&qr);
    }
    int  getf(int x)
    {
        while(x!=fa[x])
        {
            fa[x]=getf(fa[x]);
            x=fa[x];
        }
        return x;
    }
    void dfs(int u)
    {
        vis[u]=1;
        for(int i=head[u];~i;i=e[i].next)
        {
            int v=e[i].v;
            if(!vis[v])
            {
                dfs(v);
                fa[v]=u;
            }
        }
        if(q==1)
            return;
        if(u==qr&&vis[ql])
        {
            q=1;
            printf("%d
    ",getf(ql));
            return ;
        }
        if(u==ql&&vis[qr])
        {
            q=1;
            printf("%d
    ",getf(qr));
            return ;
        }
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        int kase;
        scanf("%d",&kase);
        while(kase--)
        {
            scanf("%d",&n);
            init();
            for(int i=1;i<=n;i++)
            {
                if(!flag[i])
                {
                    dfs(i);
                    break;
                }
            }
        }
        return 0;
    }

     

    第一行在线ac的,第二行是离线ac的,从时间和空间复杂度来看离线做法更加优越

    不为失败找借口,只为成功找方法
  • 相关阅读:
    HRESULT:0x80070057 (E_INVALIDARG)的异常的解决方案
    c# 取两个时间的间隔
    [转]C#算法
    智能仓库管理系统方案(四)
    分页存储过程
    ASP.NET2.0_多语言本地化应用程序(转)
    C#绘图双缓冲技术总结(转)
    C#.net同步异步SOCKET通讯和多线程总结(转)
    WIN2003 sp2中Delphi 7中的Project菜单中Options菜单打不开
    C#关于日期月天数和一年有多少周及某年某周时间段的计算
  • 原文地址:https://www.cnblogs.com/youmi/p/4517913.html
Copyright © 2020-2023  润新知