• (中等) HDU 5293 Tree chain problem,树链剖分+树形DP。


    Problem Description
     
    Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n.
    There are m chain on the tree, Each chain has a certain weight. Coco would like to pick out some chains any two of which do not share common vertices.
    Find out the maximum sum of the weight Coco can pick
     
      挺不错的一道题目,15年多校的第一场的题目,不过我太弱,比赛的时候没能想出来,赛后想了一天才把他过掉。
      刚开始的时候想法是dfs序,然后dp就好,但是好像有点问题,然后就GG了。。。
      然后想到了树形DP,想了很久才会。
      首先对于每个链,找到他两个端点的LCA,然后把这个链加到他们的LCA那里去。
      dp[i][0]表示对于i这个点,不选LCA为i的链则这颗以i为根的树最大能得到多少,dp[i][1]就是在i的链和不选i的链中最大的那一个。
      然后就是树形DP加上状态转移,dp[i][0]的话状态转移很简单,就是i的所有儿子的dp[i][1]的和就好,但是dp[i][1]这里卡了我老长时间,因为要把所有链上的点的所有非链儿子的dp[i][1]加在一起才行,然后后来想到了用减的方法算,对于某个链上的点x,他的非链儿子的dp[x][1]的和就是他的dp[x][0]减去链上儿子的dp[x][1]就好,所以就是先算出链上所有点的dp[i][0]的和,然后减去除了i的儿子之外链上所有点的dp[i][1]的和就好,再加上除了这个链之外的儿子,就能得到结果了。
      然后算和的话用树链剖分就行。
      好像动态树的话算起来更简单,但是我并不会。。。
     
    代码如下:
    // ━━━━━━神兽出没━━━━━━
    //      ┏┓       ┏┓
    //     ┏┛┻━━━━━━━┛┻┓
    //     ┃           ┃
    //     ┃     ━     ┃
    //     ████━████   ┃
    //     ┃           ┃
    //     ┃    ┻      ┃
    //     ┃           ┃
    //     ┗━┓       ┏━┛
    //       ┃       ┃
    //       ┃       ┃
    //       ┃       ┗━━━┓
    //       ┃           ┣┓
    //       ┃           ┏┛
    //       ┗┓┓┏━━━━━┳┓┏┛
    //        ┃┫┫     ┃┫┫
    //        ┗┻┛     ┗┻┛
    //
    // ━━━━━━感觉萌萌哒━━━━━━
    
    // Author        : WhyWhy
    // Created Time  : 2015年07月22日 星期三 13时55分13秒
    // File Name     : 1006.cpp
    
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <set>
    #include <map>
    #include <string>
    #include <math.h>
    #include <stdlib.h>
    #include <time.h>
    
    #pragma comment(linker, "/STACK:1024000000,1024000000")
    
    using namespace std;
    
    const int MaxN=100005;
    
    struct Edge
    {
        int to,next;
    };
    
    struct Lian 
    {
        int u,v;
        int cost;
        int next;
    };
    
    int N,M;
    
    Edge E[MaxN<<1];
    int head[MaxN],Ecou;
    
    Lian L[MaxN];
    int Lhead[MaxN],Lcou;
    
    int fa[MaxN],dep[MaxN],son[MaxN],siz[MaxN],top[MaxN],w[MaxN];
    int Tcou;
    
    int C_max[MaxN],C_wu[MaxN];
    
    void init()
    {
        Ecou=0;
        Lcou=0;
        Tcou=1;
        w[1]=1;
        top[1]=1;
        memset(Lhead,-1,sizeof(Lhead));
        memset(head,-1,sizeof(head));
    }
    
    void addEdge(int u,int v)
    {
        E[Ecou].to=v;
        E[Ecou].next=head[u];
        head[u]=Ecou++;
    }
    
    int lca(int a,int b)
    {
        while(1)
        {
            if(top[a]==top[b])
                return dep[a]<dep[b] ? a : b;
            else if(dep[top[a]]>dep[top[b]])
                a=fa[top[a]];
            else
                b=fa[top[b]];
        }
    }
    
    void addLian(int u,int v,int c)
    {
        int h=lca(u,v);
    
        L[Lcou].u=u;
        L[Lcou].v=v;
        L[Lcou].cost=c;
        L[Lcou].next=Lhead[h];
        Lhead[h]=Lcou++;
    }
    
    void dfs1(int u,int pre,int d)
    {
        int v;
    
        dep[u]=d;
        fa[u]=pre;
        siz[u]=1;
        son[u]=-1;
    
        for(int i=head[u];i!=-1;i=E[i].next)
            if(E[i].to!=pre)
            {
                v=E[i].to;
                dfs1(v,u,d+1);
                siz[u]+=siz[v];
    
                if(son[u]==-1 || siz[son[u]]<siz[v])
                    son[u]=v;
            }
    }
    
    void dfs2(int u)
    {
        if(son[u]==-1)
            return;
    
        top[son[u]]=top[u];
        w[son[u]]=++Tcou;
    
        dfs2(son[u]);
    
        int v;
    
        for(int i=head[u];i!=-1;i=E[i].next)
            if(E[i].to!=son[u] && E[i].to!=fa[u])
            {
                v=E[i].to;
                top[v]=v;
                w[v]=++Tcou;
                dfs2(v);
            }
    }
    
    void TL_init()
    {
        dfs1(1,-1,1);
        dfs2(1);
        memset(C_max,0,sizeof(C_max));
        memset(C_wu,0,sizeof(C_wu));
    }
    
    inline int lowbit(int x)
    {
        return x&(-x);
    }
    
    int sum(int x,int C[])
    {
        int ret=0;
        
        while(x>0)
        {
            ret+=C[x];
            x-=lowbit(x);
        }
    
        return ret;
    }
    
    void add(int x,int d,int C[])
    {
        while(x<=N)
        {
            C[x]+=d;
            x+=lowbit(x);
        }
    }
    
    int query(int u,int v,int C[])
    {
        int f1=top[u],f2=top[v];
        int ret=0;
    
        while(f1!=f2)
        {
            if(dep[f1]<dep[f2])
            {
                swap(f1,f2);
                swap(u,v);
            }
    
            ret+=sum(w[u],C)-sum(w[f1]-1,C);
            u=fa[f1];
            f1=top[u];
        }
    
        if(dep[u]>dep[v])
            swap(u,v);
    
        ret+=sum(w[v],C)-sum(w[u]-1,C);
    
        return ret;
    }
    
    void update(int u,int ut,int C[])
    {
        add(w[u],ut,C);
    }
    
    int dp[MaxN][2];
    
    void dfs(int u)
    {
        int v;
        int ans=0;
        int maxn=0,tsum1,tsum2;
    
        for(int i=head[u];i!=-1;i=E[i].next)
            if(E[i].to!=fa[u])
            {
                dfs(E[i].to);
                ans+=dp[E[i].to][1];
            }
    
        for(int h=Lhead[u];h!=-1;h=L[h].next)
        {
            tsum1=query(L[h].u,L[h].v,C_wu);
            tsum2=query(L[h].u,L[h].v,C_max);
            maxn=max(maxn,tsum1-tsum2+ans+L[h].cost);
        }
    
        maxn=max(maxn,ans);
        dp[u][0]=ans;
        dp[u][1]=maxn;
    
        update(u,ans,C_wu);
        update(u,maxn,C_max);
    }
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
    
        int T;
        int a,b,c;
    
        scanf("%d",&T);
    
        while(T--)
        {
            scanf("%d %d",&N,&M);
            init();
    
            for(int i=1;i<N;++i)
            {
                scanf("%d %d",&a,&b);
                addEdge(a,b);
                addEdge(b,a);
            }
    
            TL_init();
    
            while(M--)
            {
                scanf("%d %d %d",&a,&b,&c);
                addLian(a,b,c);
            }
    
            memset(dp,0,sizeof(dp));
            dfs(1);
    
            printf("%d
    ",dp[1][1]);
        }
        
        return 0;
    }
    View Code
  • 相关阅读:
    07_Python语法示例(基础语法,文件操作,异常处理)
    练习js——自动化实现12306火车票查询
    【转】app自动化问题点整理
    TouchAction的花式应用——APP九宫格绘制
    【转】web 自动化文件上传不要太简单
    阶段小测试我的作业
    Mac Chrome浏览器取消自动升级
    Mac下安装selenium及Chromedrive驱动
    【转】Jenkins配置Git push后自动构建
    函数使用练习
  • 原文地址:https://www.cnblogs.com/whywhy/p/4668406.html
Copyright © 2020-2023  润新知