d[i][0]表示不选该节点的以该节点为子树的最大欢乐值
d[i][1]表示选择该节点的以该节点为子树的最大欢乐值
staff表示员工
状态转移为
d[i][0]=sum(max(d[i-child][0],d[i-child][1]))
d[i][1]=sum(d[i-child][0])
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<list>
using namespace std;
class node
{
public:
int happy;//快乐指数
bool haveFather;//有没有父节点
list<int>child;
void init()
{
scanf("%d",&happy);
haveFather=false;
child.clear();
}
void addChild(int theChild)
{
child.push_back(theChild);
}
}staff[100010];
int d[100010][2];
//d[i][0]表示不选该节点的以该节点为子树的最大欢乐值
//d[i][1]表示选择该节点的以该节点为子树的最大欢乐值
void dp(int i,int type)//求d[i][type]
{
if(type==0)//不选此节点,d[i][0]=sum( max( d[i-child][0] , d[i-child][1] ) )
{
d[i][0]=0;
for (list<int>::iterator index=staff[i].child.begin();index!=staff[i].child.end();index++)
{
if (d[*index][0]==-1)
{
dp(*index,0);
}
if (d[*index][1]==-1)
{
dp(*index,1);
}
d[i][0]+=d[*index][0]>d[*index][1]?d[*index][0]:d[*index][1];
}
}
else//选择此节点,d[i][1]=sum ( d[i-child][0] )
{
d[i][1]=staff[i].happy;
for (list<int>::iterator index=staff[i].child.begin();index!=staff[i].child.end();index++)
{
if (d[*index][0]==-1)
{
dp(*index,0);
}
d[i][1]+=d[*index][0];
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
int n;
while (~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
staff[i].init();
}
for (int i = 0; i < n-1; i++)
{
int l,k;
scanf("%d %d",&l,&k);
staff[l].haveFather=true;
staff[k].addChild(l);
}
memset(d,-1,sizeof(d));
//初始化完毕
int ans=0;
for(int i=1;i<=n;i++)
{
if(staff[i].haveFather==false)//该节点为根节点,没有父亲节点
{
dp(i,0);
dp(i,1);
ans+=d[i][0]>d[i][1]?d[i][0]:d[i][1];
}
}
printf("%d\n",ans);
}
return 0;
}