water flow
TRANSCRIPT
問題概要
● N 個の頂点からなる木があり、それぞれ C[i]( 最初は 0) 分の水が入っている
● 次の 2 つのいずれかのクエリが M 個飛んでくるので処理する
ークエリ 1 (水を流す): v の祖先である全ての u について、 C[v] に C[u] を足し、 C[u]を 0 にする
ークエリ 2 (水を補給する): C[v] に x を足す
● 最後の C[v] をそれぞれ求める
どうやって求めるか (2)
● Euler Tour した配列に対応する配列を作り、「クエリ 1 が来た時間(クエリのインデックス)」を保存しておく
● 前からクエリを見ていくと「その頂点の子孫で最初に更新されたときに…」みたいになって難しい
オフラインクエリですが大丈夫ですか
● クエリを後ろから見ていき、先程の配列を順次更新していく
● 現在の配列の中で、子孫に対応する区間内での最小値がその水が移動するときのクエリのインデックスとなる(同時に行く頂点の番号も分かる)
● 愚直にやると O(NM)
どうやって求めるか (3)
● セグツリーで高速化する● 次に行くクエリのインデックスが求まる● 最終的に行く頂点は、次のクエリから最終的
に行く頂点● 次に行く場所がないクエリに対応する頂点に
集まるので、その頂点にクエリ 2 の水量を足せば良い
● こうして UnionFind 的に求めることができる
余談
● クエリから次に行くクエリに辺を張ると、クエリたちからなる木ができる
● よってクエリ 1 で集まる水量は子孫のクエリ2 の x の和になるので、最後の水量じゃなくそれぞれのクエリ 1 で集まった水量でも求められた
● ということに気づいたのはコンテスト中で、もう遅かった