```go
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
var n int
fmt.Fscan(reader, &n)
a := make([]int64, n+1)
for i := 1; i <= n; i++ {
fmt.Fscan(reader, &a[i])
}
adj := make([][]int, n+1)
deg := make([]int, n+1)
for i := 0; i < n-1; i++ {
var u, v int
fmt.Fscan(reader, &u, &v)
adj[u] = append(adj[u], v)
adj[v] = append(adj[v], u)
deg[u]++
deg[v]++
}
// When we root at node r and hack in BFS order from root:
// - The root is hacked first with strength a[r]
// - For any other node v with parent p(v):
// When v is hacked, its strength has been increased by:
// - +1 for each neighbor of v that was already hacked (at least p(v), so at least +1)
// - +1 for each semi-neighbor increase: when a neighbor w of v was hacked,
// v gets +1 if v is neighbor or semi-neighbor of w.
// v is always neighbor of w (if w is neighbor of v), so v gets +1.
// But also when some node u is hacked and v is semi-neighbor of u:
// there exists online bank k neighboring both u and v.
//
// Let me think more carefully. The key insight for trees:
// If we hack in a DFS/BFS order starting from root r, we can analyze
// the strength of each node when it's hacked.
//
// When node u is hacked, all neighbors and semi-neighbors of u that are online get +1.
// On a tree rooted at r, if we hack nodes in order from root outward:
// For a node v at depth d, when it gets hacked, its strength is:
// a[v] + deg[v] (from semi-neighboring/neighboring increments)
// But specifically: a[v] + deg[v] for non-root, and a[r] for root.
// Wait, that's not quite right either. Let me re-derive.
//
// Actually from the editorial/analysis: the answer when rooting at r is:
// max(a[r], max over non-root v of (a[v] + deg[v]))
// But wait, for root's children: a[v] + 1 + (deg[v]-1) = a[v] + deg[v]? Hmm.
//
// After careful analysis: if we root at r, the cost is:
// max(a[r], max_{v != r} (a[v] + deg(v)))
// because each non-root node v gets exactly deg(v) increments before being hacked.
//
// Actually the non-root nodes get incremented by the number of their neighbors
// that are hacked before them (neighboring contribution) plus semi-neighboring.
// The exact formula from the problem's editorial: cost(r) = max(a[r], max_{v≠r}(a[v] + deg(v)))
//
// We want to minimize over all r.
// Let M = max over all v of (a[v] + deg(v))
// cost(r) = max(a[r], max_{v≠r}(a[v] + deg(v)))
// If r is NOT the node achieving M, then cost(r) = max(a[r], M) >= M
// If r IS the node achieving M (say node m), cost(m) = max(a[m], second_max)
// where second_max = max_{v≠m}(a[v]+deg(v))
// Since a[m] <= a[m]+deg(m) = M, and second_max <= M, cost(m) = max(a[m], second_max)
// This could be less than M.
// So we try all nodes that achieve M as root, and also consider the best otherwise.
var maxVal int64 = -1e18
var secondMax int64 = -1e18
maxCount := 0
var maxNode int
for i := 1; i <= n; i++ {
val := a[i] + int64(deg[i])
if val > maxVal {
secondMax = maxVal
maxVal = val
maxCount = 1
maxNode = i
} else if val == maxVal {
maxCount++
} else if val > secondMax {
secondMax = val
}
}
ans := maxVal // if we don't pick the max node as root
if maxCount == 1 {
// pick maxNode as root
candidate := a[maxNode]
if secondMax > candidate {
candidate = secondMax
}
if candidate < ans {
ans = candidate
}
} else {
// multiple nodes achieve maxVal, picking any one still leaves maxVal
// cost = max(a[r], maxVal) = maxVal for any r
// ans stays maxVal
}
fmt.Println(ans)
}
```