ABC133-F:Colorful Tree
オイラーツアーとかはともかく、この解法が思いつけないのは悔しい...。
解法
まず、色の変更のことは忘れて、「木上の点間の距離を求めよ。」というクエリに効率的に答えることについて確認する。このクエリに答えるには、の最小共通祖先(LCA:Least Common Ancestor)が重要になる。木をを根とする根付き木だと思って、を頂点の根からの距離とする。をとのLCAとすれば、間の距離はと書ける。つまり、についての情報さえわかれば十分だということがわかる。LCAの効率的な述べ方については、ここでは省略するが、蟻本や検索をすれば情報は手に入るはず。
色のことを思い出してみる。ある頂点について「色の辺の距離をに変えたときに、根からの距離を求めよ。」という問いに答える必要があるが、オンラインで答えるには若干の技術が必要になる(公式解説などはこれ)。ここでは、先にすべてのクエリの情報を読み込んでしまって、その上で各クエリの答えを求めることを考えてみる。まず、各頂点に「この頂点は番目のクエリに関わり、そのクエリは色の辺の距離をにしたときのことを聞いている。」という記録をしておく。そして根からdfsをして、mapなどのデータ構造などで、「今見ている頂点をとして、に着くまでに辿った各色の辺の距離の総和と本数」を管理しておく。に来たら、保存していたクエリについて、mapのデータを参照しながら適切な計算を行う(現在の距離の総和から、色の距離の総和を引いて、(色の本数)を足す)。の子に行くときは辺の情報をmapに追加し、から帰ってきたら辺の情報を破棄すれば、全体をつのmapで処理することができ、空間計算量がで済むようになる。時間計算量はである。
実装
Submission #6307254 - AtCoder Beginner Contest 133
- LCAはいざというときのために準備しておく。それ以外の実装も量はあるが、適正帯には難しくないと思う。dfsに従って情報を入れたり捨てたりするのがポイント。
- 構造体を書くと安心感がある。