宝藏

来源:互联网 发布:2017天猫双11实时数据 编辑:程序博客网 时间:2024/04/28 23:38

题目描述
一棵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
16
提示
对于20%的数据,满足n<=10。

对于50%的数据,满足n<=1000。

对于100%的数据,满足1<=n<=3*10^5, 1<=z, ai<=10^5。

显然是一道树形dp题目。考虑回到原点与不回到原点,g[u]表示回到u的最大价值,f[u]表示不回到u的最大价值。显然有g[u]=g[u]+max(0,g[v]-len[i]*2);
f[u]=max{g[u]-g[v]-len[i]+f[v]};
然后考虑根节点的转移,同样记录向上走回与不回的最大值次大值就可以了。详见代码,可能比较丑。

varn,i,u,v,l,tot:longint;head,ret,next,len,g,a:array[-2..800000] of longint;f,p:array[-2..800000,0..2] of longint;procedure ins(u,v,l:longint);begin  tot:=tot+1;  ret[tot]:=v;  len[tot]:=l;  next[tot]:=head[u]; head[u]:=tot;end;function max(a,b:longint):longint;begin  if a>b then exit(a) else exit(b);end;procedure dfs(u,pre:longint);vari,v,s,t,vv:longint;begin  i:=head[u];  g[u]:=a[u];  while i<>0 do  begin    v:=ret[i];    if v<>pre then    begin      dfs(v,u);      g[u]:=g[u]+max(0,g[v]-len[i]*2);    end;    i:=next[i];  end;  i:=head[u];  f[u,1]:=a[u];  f[u,2]:=a[u];  while i<>0 do  begin    v:=ret[i];    if (v<>pre) then      if g[v]-len[i]*2>0 then      begin        s:=g[u]-g[v]+f[v,1]+len[i];        vv:=v;        if s>f[u,1] then        begin          t:=vv;          vv:=p[u,1];          p[u,1]:=t;          t:=s;          s:=f[u,1];          f[u,1]:=t;        end;        if s>f[u,2] then        begin          p[u,2]:=vv;          f[u,2]:=s;        end;      end      else      begin         s:=g[u]+f[v,1]-len[i];         vv:=v;         if s>f[u,1] then         begin           t:=vv;           vv:=p[u,1];           p[u,1]:=t;           t:=s;           s:=f[u,1];           f[u,1]:=t;         end;         if s>f[u,2] then         begin           p[u,2]:=vv;           f[u,2]:=s;         end;      end;    i:=next[i];  end;end;procedure find(u,pre,l:longint);vargg,ff,i,v,s,ne,t,k,nex:longint;begin  gg:=g[pre];  if g[u]-l*2>0 then gg:=gg-g[u]+l*2;  if p[pre,1]<>u then  begin    ff:=f[pre,1];    ne:=p[pre,1];    if (g[u]-l*2>0) then ff:=ff-g[u]+l*2;  end  else  begin    ff:=f[pre,2];    ne:=p[pre,2];    if (g[u]-l*2>0)and(ne<>0) then ff:=ff-g[u]+l*2;  end;        s:=f[u,1]+gg-2*l;        nex:=p[u,1];        if s>f[u,1] then        begin          t:=nex;          nex:=p[u,1];          p[u,1]:=t;          t:=s;          s:=f[u,1];          f[u,1]:=t;        end;        if s>f[u,2] then        begin          p[u,2]:=nex;          f[u,2]:=s;        end;  g[u]:=g[u]+max(0,gg-l*2);  if (gg-l*2>0) then  begin        s:=g[u]-gg+ff+l;        if s>f[u,1] then        begin          t:=ne;          ne:=p[u,1];          p[u,1]:=t;          t:=s;          s:=f[u,1];          f[u,1]:=t;        end;        if s>f[u,2] then        begin          p[u,2]:=ne;          f[u,2]:=s;        end;  end  else  begin         s:=g[u]+ff-l;         if s>f[u,1] then         begin           t:=ne;           ne:=p[u,1];           p[u,1]:=t;           t:=s;           s:=f[u,1];           f[u,1]:=t;         end;         if s>f[u,2] then         begin           p[u,2]:=ne;           f[u,2]:=s;         end;  end;  i:=head[u];  while i<>0 do  begin    v:=ret[i];    if v<>pre then      find(v,u,len[i]);    i:=next[i];  end;end;begin  readln(n);  for i:=1 to n-1 do  begin    readln(u,v,l);    ins(u,v,l);    ins(v,u,l);  end;  for i:=1 to n do    read(a[i]);  dfs(1,-1);  find(1,-1,0);  for i:=1 to n do    writeln(f[i,1]);end.
0 0
原创粉丝点击