• 2017-10-24LCA


    今天复习LCA专题,做了几道题

    其一是codevs的2370-小机房的树极其裸的一道题

    是不是很裸?直接上代码了。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define maxn 50010 
    int head[maxn],deep[maxn],dis[maxn];
    int ecnt,n,f[maxn][35];
    
    struct edge
    {
        int u,v,w;
        int next;
    }E[maxn<<1];
    
    void addedge(int u,int v,int w)
    {
        E[++ecnt].u = u;
        E[ecnt].v = v;
        E[ecnt].w = w;
        E[ecnt].next = head[u];
        head[u] = ecnt;
    }
    
    void dfs(int x,int fx)
    {
        deep[x] = deep[fx]+1;
        f[x][0] = fx;
        for(int i = head[x]; i ; i = E[i].next){
            int v = E[i].v;
            if(v == fx) continue;
            dis[v] = dis[x] + E[i].w;
            dfs(v,x);
        }
    }
    
    void init()
    {
        for(int j = 1; (1<<j) <= n; j ++)
            for(int i = 1; i <= n; i ++)
                if(deep[i] >= (1<<j))
                    f[i][j] = f[f[i][j-1]][j-1];
    }
    
    int getfather(int a,int b)
    {
        if(deep[a] < deep[b]) swap(a,b);
        int d = deep[a] - deep[b];
        for(int j = 30; j >= 0; j --)
            if(d&1<<j)
            {
                a = f[a][j];
            }
        if(a == b) return a;
        for(int j = 30; j >= 0 ; j --)
            if(f[a][j]!= f[b][j])
            {
                a = f[a][j];
                b = f[b][j];
            }
        return f[a][0];
    }
    
    int main()
    {
        scanf("%d",&n);int u,v,w,q;
        for(int i = 1; i < n; i ++)
        {
            scanf("%d%d%d",&u,&v,&w);
            u++;v++;
            addedge(u,v,w);
            addedge(v,u,w);
        }
        dfs(1,0);
        init();
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d%d",&u,&v);
            u++;v++;
            int fx = getfather(u,v);
            printf("%d
    ",dis[u]+dis[v] - 2*dis[fx]);            
        }
    }

    第二题也是codevs1036-商务旅行

    这道题乍一看以为是最短路,但是它是树上的,所以我们可以直接求每两个点的LCA然后加起来就可以了。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 30010
    using namespace std;
    int ecnt,head[maxn],deep[maxn],fa[maxn],top[maxn],size[maxn],son[maxn];
    struct edge
    {
        int u,v,next;
    }E[maxn<<1];
    
    void addedge(int u,int v)
    {
        E[++ecnt].u=u;
        E[ecnt].v=v;
        E[ecnt].next=head[u];
        head[u]=ecnt;
    }
    
    void dfs(int x)
    {
        size[x]=1;
        for(int i=head[x];i;i=E[i].next)
        {
            int v=E[i].v;
            if(fa[x]==v)continue;
            fa[v]=x;
            deep[v]=deep[x]+1;
            dfs(v);
            size[x]+=size[v];
            if(size[son[x]]<size[v])son[x]=v;    
        }
    }
    
    void dfs2(int x,int tp)
    {
        top[x]=tp;
        if(son[x])dfs2(son[x],tp);
        for(int i=head[x];i;i=E[i].next)
        {
            int v=E[i].v;
            if(v==fa[x]||v==son[x])continue;
            dfs2(v,v);
        }
    }
    
    int lca(int x,int y)
    {
        while(top[x]!=top[y])
        {
            if(deep[top[x]]<deep[top[y]])swap(x,y);
            x=fa[top[x]];
        }
        return deep[x]>deep[y]?y:x;
    }
    
    int main()
    {
        int n,tmp,m,u,v,ans=0,a;
        scanf("%d",&n);
        for(int i=1;i<n;++i)
        {
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);    
        }
        dfs(1);dfs2(1,1);
        scanf("%d%d",&m,&tmp);
        for(int i=2;i<=m;++i)
        {
            scanf("%d",&a);
            ans+=deep[tmp]+deep[a]-deep[lca(a,tmp)]*2;
            tmp=a;
        }
        printf("%d",ans);
        return 0;
    } 

    第三道题是bzoj的1787

    这道题是求三个点的最近公共祖先,我们可以先求出每两个点的LCA k1,k2,k3然后比较,假设k1==k2那么肯定选k3为集结点,如果k1为集结点,那么肯定要有两个人从k3走过来,不满足最少的题意。有思路就很舒服了。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define maxn 500005
    using namespace std;
    int ecnt,head[maxn],siz[maxn],son[maxn],deep[maxn],fa[maxn],top[maxn],n,m;
    struct edge{
        int v,next;
    }E[maxn<<1];
    void add(int u,int v)
    {
        E[++ecnt].v=v;
        E[ecnt].next=head[u];
        head[u]=ecnt;
    }
    void dfs(int x)
    {
        siz[x]=1;
        for(int i=head[x] ; i ; i=E[i].next )
        {
            int v=E[i].v;
            if(fa[x]==v)continue;
            deep[v]=deep[x]+1;fa[v]=x;
            dfs(v);
            siz[x]+=siz[v];
            if(siz[son[x]]<siz[v])son[x]=v; 
        }
    }
    void dfs2(int x,int tp)
    {
        top[x]=tp;
        if(son[x])dfs2(son[x],tp);
        for(int i=head[x] ; i ; i=E[i].next )
        {
            int v=E[i].v;
            if(son[x]==v||fa[x]==v)continue;
            dfs2(v,v);    
        } 
    }
    int lca(int x,int y)
    {
        while(top[x]!=top[y])
        {
            if(deep[top[x]]<deep[top[y]])swap(x,y);
            x=fa[top[x]];
        }
        return deep[x]<deep[y]?x:y;
    }
    inline int read()
    {
        int ret(0);
        char ch=getchar();
        while(ch>'9'||ch<'0')ch=getchar();
        while(ch>='0'&&ch<='9')
        {
            ret=(ret<<1)+(ret<<3)+ch-'0';
            ch=getchar();
        }
        return ret;
    }
    int main()
    {
        int u,v,a,b,c,t1,t2,t3,jud,tmp,fu;
        n=read();m=read();
        for(int i=1 ; i<n ; ++i )
        {
            u=read();v=read();
            add(u,v);add(v,u);
        }
        dfs(1);dfs2(1,1);
        while(m--)
        {
            a=read();b=read();c=read();
            t1=lca(a,b);t2=lca(a,c);t3=lca(b,c);
            if(t1==t2)
            {
                fu=t3;
                jud=lca(t3,a);
                tmp=deep[b]+deep[c]+deep[a]-deep[t3]-deep[jud]*2;
            }
            if(t2==t3)
            {
                fu=t1;
                jud=lca(t1,c);
                tmp=deep[b]+deep[c]+deep[a]-deep[t1]-deep[jud]*2;
            }
            if(t1==t3)
            {
                fu=t2;
                jud=lca(t2,b);
                tmp=deep[b]+deep[c]+deep[a]-deep[t2]-deep[jud]*2;
            }
            printf("%d %d
    ",fu,tmp);
        }
        return 0;
    }
  • 相关阅读:
    C语言读写伯克利DB 4
    程序之美(转自知乎)
    C语言读写伯克利DB 3
    ON DUPLICATE KEY UPDATE
    nanomsg:ZeroMQ作者用C语言新写的消息队列库
    新浪研发中心: Berkeley DB 使用经验总结
    [企业开源系列]后起之秀Facebook凭什么挑战互联网霸主Google?
    BZOJ1770:[USACO]lights 燈(高斯消元,DFS)
    BZOJ5293:[BJOI2018]求和(LCA,差分)
    BZOJ5301:[CQOI2018]异或序列(莫队)
  • 原文地址:https://www.cnblogs.com/xbygl/p/7725792.html
Copyright © 2020-2023  润新知