report - 報告 (Report) 解説 by ygussany


報告を有向辺で表したグラフを考えると,各連結成分は唯一の閉路を含み,閉路を縮約して \(1\) 頂点の根と見なすとその頂点に向かう方向に辺が向き付けられた有向木の形をしています. この有向木上の各頂点に関して,自身より番号の小さい子孫がいくつあるかが求まればよいです.(根は適当に処理すればよいです.以下の実装例では,閉路中の \(1\) 頂点を真の根として報告先を無くし,他の頂点の報告先を真の根に付け替えて木にしています.)

問題文にあるように,番号の小さい順に頂点を処理し,自身の先祖に処理済み頂点が \(1\) つ増えたという情報を伝えることを考えます. 愚直にシミュレートすると最悪 \(\Theta(N^2)\) 時間となり時間制限に間に合いませんが,各根付き木の重軽分解 (Heavy-Light Decomposition) を計算しておけば,各パス上では \(1\) 点加算区間和取得クエリまたは区間加算 \(1\) 点取得クエリとして扱うことができます. これは Fenwick 木 (Binary Indexed Tree) やセグメント木を用いて \(\mathrm{O}(\log N)\) 時間で処理でき,HL 分解の性質から \(\mathrm{O}(\log N)\) 本のパスを遡れば根に到達できるため,各頂点の処理を \(\mathrm{O}((\log N)^2)\) 時間で行うことができます. したがって,全体の計算量は \(\mathrm{O}(N (\log N)^2)\) となり十分高速です.

実装例 (C, 48 ms)

投稿日時:
最終更新: