問題
頂点 $0$ を根とする $n$ 頂点の根付き木が与えられる. 頂点 $v$ は頂点 $p_v (\lt v)$ と耐久力 $h_v$ の辺で結ばれている.
この木に対して,以下の操作を好きな回数だけ行う.
- $0$ 以外で $0$ と連結な頂点 $v$ を 1 つ選ぶ.
- $0$ と $v$ を結ぶパス上の辺の耐久力を $1$ 減らす.
- 耐久力が $0$ になった辺は削除される.
最終的な連結成分数の最大値を求めよ.
制約
- $2 \leq n \leq 5 \times 10^3$
- $1 \leq h_i \leq 10^9$
考察
$dp_{v, k} =$ 「 $v$ を根とする部分木を $k$ 個の連結成分に分解するとき, $v$ から上に伸びる辺にかかるダメージの最小値」という DP を考える. これは $v$ の各子 $u$ に対して再帰的に $dp_u$ を求めて, $v$ と $u$ を切るかどうかの処理をして,それらを左からマージしていくことで求められる.
気になるのは計算量だが,実はこれが $\Theta(n^2)$ になるというのが俗に言う「木の二乗 DP」である.これを簡単に示す.
計算量の証明
$v$ の子をそれぞれ $u_1, \cdots, u_k$ として, $u_i$ を根とする部分木のサイズを $s_i$ とする.また頂点 $v$ を根とする部分木のサイズを $n$ とする.
長さ $s, t$ の DP 配列のマージに時間 $2st$ かかるとき1,左から順にマージしていくと全体の計算量は
$$ 2 s_1 s_2 + 2 (s_1 + s_2) s_3 + \cdots + 2 (s_1 + \cdots + s_{k - 1}) s_k = 2 \sum_{i \lt j} s_i s_j = \left( \sum_{i} s_i \right)^2 - \sum_{i} {s_i}^2 $$
となる.そして $u_i$ を根とする部分木に対して DP 配列を求めるのに ${s_i}^2$ 時間かかるとすると,右辺の第 2 項が消えて $\left( \sum_{i} s_i \right)^2 = n^2$ が残る. $\square$
-
係数の $2$ は後々計算が楽なのでつけてあるだけ. ↩︎
実装例
提出 #8231839 - CPSCO2019 Session2
|
|