宝藏

来源:互联网 发布:奥斯卡终身成就奖 知乎 编辑:程序博客网 时间:2024/04/28 23:48

题目描述
一棵n个点的树,到达一个点会获得这个点上的宝藏,每个宝藏都有一定的价值。经过每条边需要支付一定的过路费。每个点只有一个宝藏,但过路费每次都要交。求从每个点出发能得到的最大收益。
输入
输入文件为treasure.in。
第一行为一个正整数n。
接下来n-1行,每行三个整数x, y, z,描述一条边的两个端点x, y和过路费z。
最后一行n个数,表示每个点上宝藏的价值ai。
输出
输出文件为treasure.out。
输出n行,每行一个数。第i行表示从i出发的最大收益。
样例输入
6
1 2 1
2 3 3
3 4 36
3 6 13
3 5 2
6 8 9 10 13 1
样例输出
30
29
28
10
30
16
提示
对于20%的数据,满足n<=10。
对于50%的数据,满足n<=1000。
对于100%的数据,满足1<=n<=3105, 1<=z, ai<=105

Solution

travel的升级版,以1为根往下做一遍,往上做一遍。
写的过程真是悲壮感人。。。(话说为什么联考里的dp全是树形的)

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#define ll long longusing namespace std;int n,x,y,z,tot;int head[300005],Next[600005],to[600005],len[600005];int a[300005];ll f[300005],g[300005];//f回到i,g不回到i ll sf[300005],sg[300005]; ll son_down[300005],son_up[300005];void add(int x,int y,int z){    tot++;    Next[tot]=head[x];    to[tot]=y;    len[tot]=z;    head[x]=tot;}void dp(int k,int pre){    f[k]=a[k];    g[k]=a[k];     ll s=0;     for(int i=head[k];i!=-1;i=Next[i])     if(to[i]!=pre)     {        dp(to[i],k);        s=s+max(0LL,f[to[i]]-2*len[i]);//去当前子树or不去    }    son_down[k]=s; //从底向下做的时候,记录k儿子的信息     f[k]=s+a[k]; //势必要回到i     for(int i=head[k];i!=-1;i=Next[i])     if(to[i]!=pre)     {        ll left=s-max(0LL,f[to[i]]-2*len[i]); //其他子树还要去         g[k]=max(g[k],left+max(g[to[i]],f[to[i]])-len[i]+a[k]);    }}void DP(int k,int pre){    ll s=0,left=0;    for(int i=head[k];i!=-1;i=Next[i])     if(to[i]!=pre) s=s+max(0LL,f[to[i]]-2*len[i]);          s=s+max(0LL,sf[k]);    for(int i=head[k];i!=-1;i=Next[i])     if(to[i]!=pre)     {        left=s-max(0LL,f[to[i]]-2*len[i]);        son_up[to[i]]=max(son_up[to[i]],left-2*len[i]);        sf[to[i]]=max(sf[to[i]],left-2*len[i]+a[to[i]]);    }    ll s1=0,s2=0;    int p1=0,p2=0;    for(int i=head[k];i!=-1;i=Next[i])     if(to[i]!=pre)     {        left=s-max(0LL,f[to[i]]-2*len[i])+g[to[i]]-len[i];        if(left>s1)         {            s2=s1;            p2=p1;            s1=left;            p1=to[i];        }        else        if(left>s2)         {            s2=left;            p2=to[i];        }    }    left=s-max(0LL,sf[k])+sg[k];    if(left>s1)     {        s2=s1;        p2=p1;        s1=left;        p1=k;    }    else    if(left>s2)     {        s2=left;        p2=k;    }    for(int i=head[k];i!=-1;i=Next[i])    if(to[i]!=pre)     {        if(p1==to[i])         {            sg[to[i]]=max(sg[to[i]],s2-len[i]+a[to[i]]-max(0LL,f[to[i]]-2*len[i]));        }        else        {            sg[to[i]]=max(sg[to[i]],s1-len[i]+a[to[i]]-max(0LL,f[to[i]]-2*len[i]));        }    }    for(int i=head[k];i!=-1;i=Next[i])     if(to[i]!=pre) DP(to[i],k);}int main(){    cin>>n;    for(int i=1;i<=n;i++) head[i]=-1;    for(int i=1;i<n;i++)     {        scanf("%d%d%d",&x,&y,&z);        add(x,y,z);        add(y,x,z);    }    for(int i=1;i<=n;i++)     {        scanf("%d",&a[i]);        sf[i]=sg[i]=a[i];    }    dp(1,0);    DP(1,0);    for(int i=1;i<=n;i++) printf("%lld\n",max(max(sf[i]+f[i]-a[i],g[i]+son_up[i]),sg[i]+son_down[i]));    return 0;}
0 0
原创粉丝点击