2015蓝桥杯省赛第10题: 生命之树

在X森林里,上帝创建了生命之树。

他给每棵树的每个节点(叶子也称为一个节点)上,都标了一个整数,代表这个点的和谐值。
上帝要在这棵树内选出一个非空节点集S,使得对于S中的任意两个点a,b,都存在一个点列 { a , v 1 , v 2 , … , v k , b } \{a, v_1, v_2,\dots,v_k, b\} {a,v1,v2,,vk,b} 使得这个点列中的每个点都是S里面的元素,且序列中相邻两个点间有一条边相连。
在这个前提下,上帝要使得S中的点所对应的整数的和尽量大。
这个最大的和就是上帝给生命之树的评分。

经过的努力,他已经知道了上帝给每棵树上每个节点上的整数。但是由于不擅长计算,他不知道怎样有效的求评分。他需要你为他写一个程序来计算一棵树的分数。

input

5
1 -2 -3 4 5
4 2
3 1
1 2
2 5

output

8

思路:树形 d p dp dp,令 d p [ i ] dp[i] dp[i] i i i为根的子树最大答案。
显然对于结点 u u u选取子结点为正的 d p [ v ] dp[v] dp[v]相加转移即可。
d p [ u ] + = d p [ v ]   ( d p [ v ] > 0 ) dp[u]+=dp[v]\ (dp[v]>0) dp[u]+=dp[v] (dp[v]>0)
注意需要初始化 a n s = − i n f ans=-inf ans=inf,因为结点的权值可能都为负,这样答案就是负。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define pb push_back
ll dp[N];
int n;
ll ans=-inf;
vector<int>e[N];
void dfs(int u,int fa){
	for(int v:e[u]){
		if(v==fa) continue;
		dfs(v,u);
		if(dp[v]>0) dp[u]+=dp[v];
	}
	ans=max(ans,dp[u]);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&dp[i]);
	for(int i=1,u,v;i<n;i++){
		scanf("%d%d",&u,&v);
		e[u].pb(v),e[v].pb(u);
	}
	dfs(1,0);
	printf("%lld\n",ans);
	return 0;
}