Hdu-5834 Magic boy Bi Luo with his excited tree(树形DP)

Problem Description
Bi Luo is a magic boy, he also has a migic tree, the tree has  N  nodes , in each node , there is a treasure, it's value is  V[i] , and for each edge, there is a cost  C[i] , which means every time you pass the edge  i  , you need to pay  C[i] .

You may attention that every  V[i]  can be taken only once, but for some  C[i]  , you may cost severial times.

Now, Bi Luo define  ans[i]  as the most value can Bi Luo gets if Bi Luo starts at node  i .

Bi Luo is also an excited boy, now he wants to know every  ans[i] , can you help him?
 

Input
First line is a positive integer  T(T104)  , represents there are  T  test cases.

Four each test:

The first line contain an integer  N (N105) .

The next line contains  N  integers  V[i] , which means the treasure’s value of node  i(1V[i]104) .

For the next  N1  lines, each contains three integers  u,v,c  , which means node  u  and node  v  are connected by an edge, it's cost is  c(1c104) .

You can assume that the sum of  N  will not exceed  106 .
 

Output
For the i-th test case , first output Case #i: in a single line , then output  N  lines , for the i-th line , output  ans[i]  in a single line.
 

Sample Input
  
  
1 5 4 1 7 7 7 1 2 6 1 3 1 2 4 8 3 5 2
 

Sample Output
 
 
Case #1: 15 10 14 9 15
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define INF 0x3f3f3f3f
#define eps 1e-9
#define MAXN 100005
using namespace std;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}  
struct thing
{
	int v,value;
	thing(int a,int b)
	{
		v = a,value = b;
	}
};
vector <thing> G[MAXN];
int T,n,f[MAXN][2],cho[MAXN],bac[MAXN],nbac[MAXN],snbac[MAXN],val[MAXN],Fa[MAXN],faval[MAXN],ans[MAXN],up[MAXN][2];
void dfs(int u,int fa)
{
	Fa[u] = fa;
	int child = 0;
	for(thing v : G[u])
	if(v.v != fa) dfs(v.v,u);
	else faval[u] = v.value;
	for(thing v : G[u])
	 if(v.v != fa) 
	 {
	 	child++;
	 	int Val = v.value;
	    if(f[child-1][1] + max(0,nbac[v.v] - Val) > f[child-1][0] + max(0,bac[v.v]- 2*Val))
	 	{
	 		f[child][0] = f[child-1][1] + max(0,nbac[v.v] - Val);
	 		cho[u] = v.v;
 		}			
 		else f[child][0] = f[child-1][0] + max(0,bac[v.v]- 2*Val);
		f[child][1] = f[child-1][1] + max(0,bac[v.v] - 2*Val);		
	}
	if(!child) bac[u] = nbac[u] = max(0,val[u]);
	else 
	{
		bac[u] = val[u] + f[child][1];
		nbac[u] = val[u] + f[child][0];
	}
	child = 0;
	for(thing v : G[u])
	 if(v.v != fa) 
	 {
	 	child++;
	 	int Val = v.value;
	 	if(f[child-1][1] + max(0,nbac[v.v] - Val) > f[child-1][0] + max(0,bac[v.v]- 2*Val) && v.v != cho[u])
	 	{
	 		f[child][0] = f[child-1][1] + max(0,nbac[v.v] - Val);
	 	}
 		else f[child][0] = f[child-1][0] + max(0,bac[v.v]- 2*Val);
	}
	snbac[u] = val[u] + f[child][0];
}
void dfs2(int u,int fa)
{
	if(fa > 0)
	{
		int f0,f1;
		if(u != cho[fa]) f0 = nbac[fa] - max(0,bac[u] - 2*faval[u]);
		else f0 = snbac[fa] - max(0,bac[u] - 2*faval[u]);
		f1 = bac[fa] - max(0,bac[u] - 2*faval[u]);
		if(Fa[fa] > 0)
		{
			f0 = max(f0 + max(0,up[fa][1]),f1 + max(0,up[fa][0]));
			f1 += max(0,up[fa][1]);
		} 
		up[u][0] = max(0,f0 - faval[u]);
		up[u][1] = max(0,f1 - 2*faval[u]);
		ans[u] = max(max(up[u][1],0)+max(0,nbac[u]),max(up[u][0],0)+max(0,bac[u])); 
	}
	else ans[u] = nbac[u];
	for(thing v : G[u])
	 if(v.v != fa) dfs2(v.v,u);
}
int main()
{
	T = read();
	for(int t = 1;t <= T;t++)
	{
		n = read();
		for(int i = 1;i <= n;i++)
		{
			val[i] = read();
			G[i].clear();
		}
		for(int i = 1;i < n;i++)
		{
			int u,v,Val;
			u = read(),v = read(),Val = read();
			G[u].push_back(thing(v,Val));
			G[v].push_back(thing(u,Val));
		}
		dfs(1,-1);
		dfs2(1,-1);
		printf("Case #%d:\n",t);
		for(int i = 1;i <= n;i++) printf("%d\n",ans[i]);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值