DFS+BFS Numberingで部分木の任意深さのクエリを処理する
Tree Depth Query by BFS Numberingについては Tree Depth Query by BFS Numbering - niuez.github.ioを参照してください.
# 処理したいクエリ (例)
有向木が与えられ, 各頂点には重みがある.
- 頂点$v$から, 辺をちょうど$d$個たどって到達できる頂点の重みの総和を出力
総和じゃなくても更新とかもしたいよね.
# アルゴリズム
BFS Numberingをすると, 同じ深さの頂点が並ぶということは上の記事をみるとわかります. これにDFS Euler Tourしたときの情報を合わせることで任意深さについで, BFS Euler Tourしたときの区間を前計算$O(N)$, クエリ$O(\log N)$で求めることができます.
BFS Numberingしたときの順番と, DFS Numberingしたときの$in/out$を各ノードに添えました. ただし, ノードの子供を探索する順序はDFS, BFS共に同じにします, すると,
- 深さ$0$のノードのbfsの番号と$in$
|
|
- 深さ$1$のノードのbfsの番号と$in$
|
|
- 深さ$2$のノードのbfsの番号と$in$
|
|
- 深さ$3$のノードのbfsの番号と$in$
|
|
となり, 単調増加します.
また, DFS Numberingでは, ある頂点$v$の$[in, out)$は, $v$を根とする部分木に含まれる頂点の$in$の集合です. これを活かして, 頂点$1$から深さ$2$の頂点のBFS Numberingの区間を求めてみます.
木全体での頂点$1$の深さは$1$なので, 求めたい区間の頂点は深さ$3$です.
また, 頂点$1$の$[in, out)$は$[1, 8)$です. なので求めたい頂点の$in$の値は, 深さ$3$での$in$の列の中で$[1, 8)$に含まれている$in = 3, 4, 6, 7$です.
これは, BFS Numberingの区間では$[7, 10)$に相当します.
この操作は二分探索で行うことができるので, クエリあたり$O(\log N)$です.
# 実装
para[i] := BFS Numberingでi番目の頂点
inv_para[v] := BFS Numberingにおける頂点vのインデックス
|
|
# 使用例
No.899 γathereeを解いてみました. #448690 (C++14) No.899 γatheree - yukicoder
# verify問題
びーと, ありがとう