import sys # sortedcontainersライブラリをインポート try: from sortedcontainers import SortedList except ImportError: print("エラー: 'sortedcontainers' ライブラリが必要です。", file=sys.stderr) print(" pip install sortedcontainers ", file=sys.stderr) sys.exit(1) # 再帰深度の上限を増やす sys.setrecursionlimit(200010) def main(): # 高速I/O n_str = sys.stdin.readline() if not n_str: return n = int(n_str) w = list(map(int, sys.stdin.readline().split())) graph = [[] for _ in range(n)] for _ in range(n - 1): a, b = map(int, sys.stdin.readline().split()) a -= 1 b -= 1 graph[a].append(b) graph[b].append(a) # --- dfs1: 各ノードを根とする部分木の重みの合計を計算 --- sum_subtree = list(w) def dfs1(i, p): for c in graph[i]: if c == p: continue sum_subtree[i] += dfs1(c, i) return sum_subtree[i] dfs1(0, -1) total = sum_subtree[0] ans = 1 << 60 # --- update: 答えを更新するヘルパー関数 --- def update(s1, s2): nonlocal ans s3 = total - s1 - s2 if s3 < 0: # 3分割が不可能な場合は無視 (念のため) return mx = max(s1, s2, s3) mn = min(s1, s2, s3) ans = min(ans, mx - mn) # --- dfs2: Small-to-Large Merging (SortedListを使用) --- def dfs2(i, p): """ SortedListを使い、O(N log^2 N)で最適解を探す。 """ # C++: new set() -> Python: SortedList() sums = SortedList() current = sum_subtree[i] remain = total - current for c in graph[i]: if c == p: continue # 子ノードの結果セット(SortedList)を取得 res = dfs2(c, i) # --- Logic 1: (remain, *itr, current - *itr) --- # resは既にソート済みなので、ソート不要 if res: # C++: res->lower_bound(current / 2) # O(log |res|) idx = res.bisect_left(current / 2) if idx < len(res): update(remain, res[idx]) # C++の *itr if idx > 0: update(remain, res[idx - 1]) # C++の *--itr # --- Small-to-Large Merging の最適化 --- # `sums` が常に `res` より大きい (か等しい) ようにスワップする if len(sums) < len(res): sums, res = res, sums # --- Logic 2: (e, *itr, total - e - *itr) --- # `sums` も既にソート済みなので、ソート不要 if sums: # `res` (小さいセット) の各要素 e について # O(|res|) for e in res: # O(log |sums|) idx = sums.bisect_left((total - e) / 2) if idx < len(sums): update(e, sums[idx]) if idx > 0: update(e, sums[idx - 1]) # --- マージ --- # C++: sums->insert(all(*res)); # O(|res| * log |sums|) sums.update(res) # Note: # C++の set::insert(range) は O(|res| * log(|sums| + |res|)) # SortedList.update() も O(|res| * log(|sums|)) # よって、ここの計算量もC++とオーダーレベルで一致する # 最後に自分自身の部分木の合計もセットに追加 # O(log |sums|) sums.add(current) return sums dfs2(0, -1) print(ans) if __name__ == "__main__": main()