题意:有一棵树包含n个点,n-1条边,每个点有个值value[i],每条边有边权(即费用),问你以每个点作为开始点,向其他点走,走到一个点可以得到这个点的value,经过一条边会有费用,费用由value值支付,每个点的value值只能拿一次,没必要所有点都走到,问你可以得到的最大的value值,当value值不足以支付边权时也可以走。
分析:显而易见的树形dp,如果只从一个点出发,那么这个题就成了很裸的树形dp,关键这个题是要从每个点出发求相应的答案,我们只需要第二次dfs的时候找出每个点的答案即可。方法来源于上决——
#include<bits/stdc++.h>
using namespace std;
#define maxn 100010
int val[maxn];
int p[maxn],num;
struct node
{
int u,v,len,next;
node(){}
node(int u,int v,int len,int next): u(u),v(v),len(len),next(next) {}
}E[maxn*2];
void init()
{
num=0;
memset(p,-1,sizeof(p));
}
void add(int u,int v,int len)
{
E[num]=node(u,v,len,p[u]);
p[u]=num++;
}
int max_back[maxn],max_notback[maxn],max_notback_id[maxn];
int submax_notback[maxn];
int ans[maxn];
void dfs1(int u,int fa)
{
max_back[u]=max_notback[u]=val[u];
submax_notback[u]=0;
for(int i=p[u];~i;i=E[i].next)
{
int v=E[i].v;
int len=E[i].len;
if(v==fa) continue;
dfs1(v,u);
}
for(int i=p[u];~i;i=E[i].next)
{
int v=E[i].v;
int len=E[i].len;
if(v==fa) continue;
max_back[u]+=max(0,max_back[v]-2*len);
}
for(int i=p[u];~i;i=E[i].next)
{
int v=E[i].v;
int len=E[i].len;
if(v==fa) continue;
int Len=max_back[u]-max(0,max_back[v]-2*len)+max(0,max_notback[v]-len);
if(Len>max_notback[u])
{
submax_notback[u]=max_notback[u];
max_notback[u]=Len;
max_notback_id[u]=v;
}
else if(Len>submax_notback[u])
{
submax_notback[u]=Len;
}
}
}
void dfs2(int u,int fa,int fa_back,int fa_notback)
{
ans[u]=max(fa_back+max_notback[u],fa_notback+max_back[u]);
for(int i=p[u];~i;i=E[i].next)
{
int v=E[i].v;
int len=E[i].len;
if(v==fa) continue;
int fb,fnb;
if(v==max_notback_id[u])
{
fb=fa_back+max_back[u]-max(0,max_back[v]-2*len);
fnb=max(fa_notback+max_back[u]-max(0,max_back[v]-2*len),
fa_back+submax_notback[u]-max(0,max_back[v]-2*len));
}
else
{
fb=fa_back+max_back[u]-max(0,max_back[v]-2*len);
fnb=max(fa_notback+max_back[u]-max(0,max_back[v]-2*len),
fa_back+max_notback[u]-max(0,max_back[v]-2*len));
}
dfs2(v,u,max(0,fb-2*len),max(0,fnb-len));
}
}
int main()
{
int T;
scanf("%d",&T);
for(int ca=1;ca<=T;ca++)
{
init();
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&val[i]);
for(int i=1;i<n;i++)
{
int u,v,len;
scanf("%d%d%d",&u,&v,&len);
add(u,v,len);
add(v,u,len);
}
dfs1(1,-1);
dfs2(1,-1,0,0);
printf("Case #%d:\n",ca);
for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
}
return 0;
}