//树形dp入门第一题
// 题意: 给一棵树每个节点都有权值 子节点和父节点不能同时取 问能取得权值之和最大是多少 看似有向边其实为无向边//
//从任意一个节点x dfs到叶节点 并计算叶节点的值 然后边回溯边dp 求当前节点的最优状态 当回溯到x时整棵树的最优解就得到了
//dp[x][0]表示不取节点x得到的最优解 dp[x][1]表示取节点x 当取该节点时 就不能取它的父节点(y)和子节点(z)了 所以 dp[x][1]=dp[z][0]+dp[y][0]+num[x];
//不取当前节点 则可以取父节点和子结点 也可以不取 取两者的最大值结可以了 dp[x][0]+=max(dp[k][0],dp[k][1])(k为x的父节点或子结点)
//
// 树 5
// / \
// 3 4
// / \ / \
// 1 2 6 7
//
//的邻接表建成是这个样子的(建双向边)
//head[1]->3->^
//head[2]->3->^
//head[3]->1->2->5->^
//head[4]->6->7->5->^
//head[5]->3->4->^
//head[6]->4->^
//head[7]->4->^
//
//
#include<stdio.h>
#include<string.h>
#define N 6100
struct node
{
int v;
struct node * next;
}*head[N],tree[N*2];//邻接表的节点 v 存树的节点的编号
int dp[N][2];
int num[N];
int vis[N];
int n,p;
int max(int a,int b){return a>b?a:b;}
void add(int a,int b)//加边 建邻接表 单链表头插法
{
tree[p].v=b;
tree[p].next=head[a];head[a]=&tree[p++];
tree[p].v=a;
tree[p].next=head[b];head[b]=&tree[p++];
}
void init()
{
p=1;
memset(vis,0,sizeof(vis));
memset(head,NULL,sizeof(head));
memset(dp,0,sizeof(dp));
int i;
for(i=1;i<=n;i++)
scanf("%d",&num[i]);
int a,b;
while(scanf("%d%d",&a,&b),(a+b))
{
add(b,a);
}
return ;
}
void tree_dp(int x)
{
if(vis[x])return ;
vis[x]=1;
int temp,i;
struct node * pp;
pp=head[x];
while(pp)
{
if(!vis[pp->v])//vis[pp->v]=1时 说明当前的pp求pp->v dfs过来 所以不能再dfs回去 需要回溯回去
{
tree_dp(pp->v);
temp=max(dp[pp->v][0],dp[pp->v][1]);
dp[x][0]+=temp;
dp[x][1]+=dp[pp->v][0];
}
pp=pp->next;
}
dp[x][1]+=num[x];
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
init();
tree_dp(1);
printf("%d\n",max(dp[1][0],dp[1][1]));
}
return 0;
}