結果
| 問題 |
No.3348 Tree Balance
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-10-25 16:24:45 |
| 言語 | Python3 (3.13.1 + numpy 2.2.1 + scipy 1.14.1) |
| 結果 |
TLE
|
| 実行時間 | - |
| コード長 | 4,530 bytes |
| コンパイル時間 | 88 ms |
| コンパイル使用メモリ | 12,416 KB |
| 実行使用メモリ | 129,548 KB |
| 最終ジャッジ日時 | 2025-11-13 20:53:31 |
| 合計ジャッジ時間 | 12,831 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | TLE * 1 -- * 24 |
ソースコード
# By Gemini
import sys
def solve():
# 再帰深度を深く設定
# N が大きい場合 (例: 2*10^5) に備える
sys.setrecursionlimit(200010)
# --- 入力処理 ---
try:
N = int(sys.stdin.readline())
W = list(map(int, sys.stdin.readline().split()))
adj = [[] for _ in range(N)]
edges = [] # 辺 (u, v) を (0-indexed) で保存
for _ in range(N - 1):
A, B = map(int, sys.stdin.readline().split())
u, v = A - 1, B - 1
adj[u].append(v)
adj[v].append(u)
edges.append((u, v))
except EOFError:
return
except Exception as e:
# print(f"Input Error: {e}", file=sys.stderr)
return
# N < 3 の場合、辺を2本選べないが、問題文の前提 (N-1本の木) から
# N >= 3 と想定される。
if N < 3:
print(0)
return
# --- 全頂点の重みの総和 ---
total_sum = sum(W)
# --- 根付き木 (頂点0を根) の情報を計算 (DFS) ---
parent = [-1] * N # parent[v]: 頂点vの親
subtree_sum = [0] * N # subtree_sum[v]: vを根とする部分木の重み総和
in_time = [-1] * N # in_time[v]: DFSの行きがけ順
out_time = [-1] * N # out_time[v]: DFSの帰りがけ順
timer = [0] # DFSの時刻 (ミュータブルなリストとして渡す)
def dfs(v, p):
parent[v] = p
in_time[v] = timer[0]
timer[0] += 1
s = W[v] # 自身の重み
for u in adj[v]:
if u == p:
continue
dfs(u, v)
s += subtree_sum[u] # 子の部分木の重みを加算
subtree_sum[v] = s
out_time[v] = timer[0]
timer[0] += 1
# 頂点0を根としてDFSを実行
dfs(0, -1)
# --- 祖先判定関数 (O(1)) ---
# u が v の祖先 (u == v も含む) かどうか
def is_ancestor(u, v):
return in_time[u] <= in_time[v] and out_time[v] <= out_time[u]
# --- 各辺 (N-1本) に対応する「子ノード」を特定 ---
# 辺 (u, p) を削除したとき、p側 (根側) と u側 (子側) に分かれる。
# u (子ノード) の subtree_sum[u] が切り出される部分木の重み和となる。
child_nodes = []
for u, v in edges:
if parent[v] == u:
# v が u の子
child_nodes.append(v)
else:
# u が v の子
child_nodes.append(u)
# child_nodes には N-1 個の頂点インデックスが入る
min_diff = float('inf')
# --- 2本の辺 (i, j) を全探索 O(N^2) ---
num_edges = N - 1
for i in range(num_edges):
v1 = child_nodes[i]
S_A = subtree_sum[v1] # 辺iの削除で切り出される部分木の重み和
for j in range(i + 1, num_edges):
v2 = child_nodes[j]
S_B = subtree_sum[v2] # 辺jの削除で切り出される部分木の重み和
sums = []
# 場合分け:
# 1. v1 が v2 の祖先 (辺iが辺jより根に近い)
if is_ancestor(v1, v2):
S1 = S_B # v2の部分木
S2 = S_A - S_B # v1の部分木からv2の部分木を除いたもの
S3 = total_sum - S_A # v1の親側 (全体からv1の部分木を除いたもの)
sums = [S1, S2, S3]
# 2. v2 が v1 の祖先 (辺jが辺iより根に近い)
elif is_ancestor(v2, v1):
S1 = S_A # v1の部分木
S2 = S_B - S_A # v2の部分木からv1の部分木を除いたもの
S3 = total_sum - S_B # v2の親側 (全体からv2の部分木を除いたもの)
sums = [S1, S2, S3]
# 3. v1 と v2 が祖先-子孫関係にない (並列な部分木)
else:
S1 = S_A # v1の部分木
S2 = S_B # v2の部分木
S3 = total_sum - S_A - S_B # それ以外 (根を含む部分)
sums = [S1, S2, S3]
# (最大値 - 最小値) の最小値を更新
diff = max(sums) - min(sums)
if diff < min_diff:
min_diff = diff
# --- 出力 ---
print(min_diff)
if __name__ == "__main__":
solve()