int N;
vector<int> links[10010];
int apple[10010];
struct Node{
/*
이때 subtree는 두가지 경우가 있음
1. 자식 노드의 subtree의 값이 더 큰경우
2. 자식 노드 두개까지 경로의 가중치 합 + 해당 노드의 가중치 합이 더 큰 경우
*/
pii subtree; // 해당 노드를 지나는 서브트리에서 최적 값 (최대 사과 개수, 최소 인덱스)
pii leaf; // 해당 노드 ~ 리프 노드 사이에서 최적 값 (최대 사과 개수, 최소 인덱스)
// 간단한 max 연산을 위해 인덱스는 음수로 저장
};
Node DP[10010];
void dfs(int cur, int par){
pii bestSub = {apple[cur], -cur};
pii bestLeaf = {apple[cur], -cur};
vector<pii> childLeafs;
for(auto nxt: links[cur]){
if(nxt == par) continue;
dfs(nxt, cur);
bestSub = max(bestSub, DP[nxt].subtree); // 1번 경우
// 가장 이득인놈 두개만 남기면 됨
childLeafs.push_back(DP[nxt].leaf);
sort(all(childLeafs), greater<pii>());
if((int)childLeafs.size() > 2) childLeafs.pop_back();
}
if((int)childLeafs.size() >= 2){ // 2번 경우
pii cand = {apple[cur] + childLeafs[0].first + childLeafs[1].first, max(childLeafs[0].second, childLeafs[1].second)};
bestSub = max(bestSub, cand);
}
if((int)childLeafs.size() >= 1){
pii cand = {apple[cur] + childLeafs[0].first, childLeafs[0].second};
bestLeaf = max(bestLeaf, cand);
}
pii cand = {bestLeaf.first, max(bestLeaf.second, -cur)};
bestSub = max(bestSub, cand);
DP[cur].subtree = bestSub;
DP[cur].leaf = bestLeaf;
}
void solve(){
cin >> N;
rep(i, 1, N+1) cin >> apple[i];
rep(i, 0, N-1){
int u, v; cin >> u >> v;
links[u].push_back(v);
links[v].push_back(u);
}
dfs(1, -1);
cout << DP[1].subtree.first << ' ' << -DP[1].subtree.second << '\n';
}