/*/
题意:
有N个村庄,每个村庄有一个权值,有n-1条路,将村庄连起来,然后选取这些路中的一个联通图,权值最大。
整个图都被联通,找其中权值最大的子联通块。
树状DP。
代码风格学了某个学长的写了个结构体,真刺激。。

AC代码:
/*/
#include"algorithm"
#include"iostream"
#include"cstring"
#include"cstdlib"
#include"cstdio"
#include"string"
#include"vector"
#include"queue"
#include"cmath"
using namespace std;
typedef long long LL ;
#define memset(x,y) memset(x,y,sizeof(x))
#define memcpy(x,y) memcpy(x,y,sizeof(x))
#define FK(x) cout<<"["<<x<<"]
"
#define bigfor(x) for(LL qq=1;qq<= T ;qq++)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int MX = 16666;
struct Treedp {
struct Edge {
int v,nxt;
} E[MX<<1];
int Head[MX],erear;
bool vis[MX];
int dp[MX];
int INF=-1e9-1e5;
void init() {
erear=0;
memset(E,0);
memset(vis,0);
memset(Head,-1);
}
void add(int u,int v) {
E[erear].v=v;
E[erear].nxt=Head[u];
Head[u]=erear++;
}
int run(int u) {
vis[u]=1;
for(int i=Head[u]; ~i; i=E[i].nxt) {
int v=E[i].v;
if(!vis[v]) {
dp[u]+=max(0,run(v));
}
}
return dp[u];
}
void print(int n) {
for(int i=1; i<=n; i++)
cout<<dp[i]<<" ";
puts("");
}
};
Treedp tdp;
int main() {
int n,l,r;
scanf("%d",&n);
tdp.init();
for(int i=1; i<=n; i++) {
scanf("%d",&tdp.dp[i]);
}
for(int i=1; i<n; i++) {
scanf("%d%d",&l,&r);
tdp.add(l,r);
tdp.add(r,l);
}
int maxx=-1e9-1000000;
tdp.run(1);
for(int i=1; i<=n; i++) {
maxx=max(maxx,tdp.dp[i]);
}
// tdp.print(n);
printf("%d
",maxx);
return 0;
}