zoukankan      html  css  js  c++  java
  • (中等) 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
  • 相关阅读:
    使用私有api实现自己的iphone桌面,并根据app的使用次数对app排序
    坐标系的属性
    带坐标轴的几何画板
    空间几何体的直观图matlab
    设置npm的registry
    (原创)机器学习之numpy库中常用的函数介绍(一)
    (原创)交叉编译 tesseract
    (原创)计算机视觉之数学原理-基础篇
    (原创)nRF51 DFU 初始化包介绍及生成工具
    (原创)使用nRF51822/nRF51422创建一个简单的BLE应用 ---入门实例手册(中文)之五
  • 原文地址:https://www.cnblogs.com/whywhy/p/4668406.html
Copyright © 2011-2022 走看看