本题可用树形DP求解(即在树上DP).
father数组记录节点父亲,ch容器记录儿子。
dp[i][0]表示以节点i为跟的子树的最大总权值(不选点i),dp[i][1]表示选点i。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cmath>
#define ll __int64
#define INF 0x3fffffff
#define MAXN 6005
using namespace std;
int n;
int dp[MAXN][2];
int a[MAXN],father[MAXN],vis[MAXN];
vector<vector<int> >ch(6005);
void tree_dp(int root)
{
vis[root]=1;
for(int i=0;i<ch[root].size();i++) {
int j=ch[root][i];
if(!vis[j]) {
tree_dp(j);
dp[root][0]+=max(dp[j][1],dp[j][0]);
dp[root][1]+=dp[j][0];
}
}
}
int main()
{
//freopen("d:\\Test.txt","r",stdin);
while(~scanf("%d",&n)) {
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
memset(vis,0,sizeof(vis));
memset(dp,0,sizeof(dp));
memset(father,0,sizeof(father));
for(int i=0;i<=n;i++) ch[i].clear();
for(int i=1; i<=n; i++) dp[i][1]=a[i];
int c,f;
while(scanf("%d%d",&c,&f),c||f) {
father[c]=f;
ch[f].push_back(c);
}
int root=1;
while(father[root]) root=father[root];
tree_dp(root);
cout<<max(dp[root][0],dp[root][1])<<endl;
}
return 0;
}