最遠点を求めた後にLink-Cut Treeで回移動する解法で解いてみました。
ここでは、Link-Cut Treeの詳細な説明は割愛し、必要な部分だけを記載します。
詳細は以下のサイトを見るのが良いと思います。
Link-Cut Treeの実装メモ - 日々drdrする人のメモ
Link-Cut木では、以下のような操作ができます。
:頂点
を根にする
:根から頂点
までのパスをHeavy-edgeで繋ぐ(パス上の頂点から出るその他の辺は全てLight-edgeになる)
頂点を根とし、頂点
までのパスをHeavy-edgeで繋ぐと、
間に含まれる全ての頂点が同一の平衡二分探索木によって管理されます。
この平衡二分探索木の頂点を通りがけ(in-order)順に並べると間のパス順になるようになっています。
続いて、平衡二分探索木を通りがけ順に並べた時の番目の頂点を高速に得る方法を考えます。
まず、平衡二分探索木に部分木のサイズを持たせます。すると、通りがけ順で番目となる頂点が、今いる頂点
の左部分木か、右部分木か、
自身かというのが、以下の場合分けで判定できます。 なお、1-indexedで並べるものとします。
=頂点
の左部分木のサイズ+1
とします。+1は頂点の分です。
の場合
通りがけ順では、左部分木を全て並べた後、頂点を並べます。
左部分木のの頂点を並べた後に、
番目として
を並べるので、このケースでは
を返せば良いです。
の場合
左部分木に番目が存在するので、
の左の子の
番目を調べます。
の場合
右部分木に番目が存在するので、
の右の子について、
個の頂点を除いた
番目を調べます。
このように根から順に二分探索のような感じで調べていくことで番目の頂点を得ることが可能です。
計算量は、平衡二分探索木の高さ分の探索をするので、平衡二分探索木であることを考えると、ならしlog時間くらいになると思われます。
以上から、元の問題を以下のように解くことができます。
- 頂点
からの最遠点
を、すべての頂点について求める
- 各クエリで与えられるの頂点
をLink-Cut Treeの根とし、最遠点
を根と繋ぐ
から
までのパス上における
番目の頂点をLink-Cut Treeの平衡二分探索木から求める
計算量を考えます。
最遠点は、全方位木DPにより求めたので、です。
Link-Cut Treeで行う各処理は、で処理できると思うので、
です(おそらく)。
よって、全体でだと思います。
提出コード:Submission #34979495 - NEC Programming Contest 2022 (AtCoder Beginner Contest 267)
Link-Cut Treeにはモノイドを乗せるようにしてあるので、構造体等が定義されていますが、この問題を解くにあたっては不要です。