water flow

23
NPCA Programming Contest Alpha #3 #76 流しそうめん

Upload: ryunosuke-iwai

Post on 31-Jul-2015

1.388 views

Category:

Art & Photos


0 download

TRANSCRIPT

NPCA Programming Contest Alpha #3#76 流しそうめん

問題概要

● N 個の頂点からなる木があり、それぞれ C[i]( 最初は 0) 分の水が入っている

● 次の 2 つのいずれかのクエリが M 個飛んでくるので処理する

ークエリ 1 (水を流す): v の祖先である全ての u について、 C[v] に C[u] を足し、 C[u]を 0 にする

ークエリ 2 (水を補給する): C[v] に x を足す

● 最後の C[v] をそれぞれ求める

愚直な方法

● クエリ 1 を愚直に処理する● クエリ 2 を愚直に処理する● 計算量は O(( 木の深さ )×M) くらい

→ 最悪計算量は O(NM) ぐらい

→ 死

                    逆に考えるんだ

逆に考える

「水がどこから来るか」を考えるのではなく、

「今ある水がどこに行くか」を考える

1

2 3

5 6

4

7 8

+101 : 1 に +10

1

2 3

5 6

4

7 8

+10

2 : 2 に集める

1

2 3

5 6

4

7 8

+5

3 : 4 に +5

+10

1

2 3

5 6

4

7 8

+5

4 : 2 に集める

+10

1

2 3

5 6

4

7 8+5

5 : 6 に集める

+10

1

2 3

5 6

4

7 8+5

6 : 5 に集める

+10

1

2 3

5 6

4

7 8+5

7 : 1 に +3

+10

+3

1

2 3

5 6

4

7 8+5

8 : 7 に集める

+10 +3

考察

ある頂点にある水は、その子孫の頂点のうち、

「その後クエリ 1 が一番最初に来た頂点」に移動することが分かる

どうやって求めるか (1)

● 頂点の子孫は Euler Tour を使って一次元配列の区間にできる

● 詳しくは蟻本など参照

どうやって求めるか (2)

● Euler Tour した配列に対応する配列を作り、「クエリ 1 が来た時間(クエリのインデックス)」を保存しておく

● 前からクエリを見ていくと「その頂点の子孫で最初に更新されたときに…」みたいになって難しい

                    逆に考えるんだ

オフラインクエリですが大丈夫ですか

● クエリを後ろから見ていき、先程の配列を順次更新していく

● 現在の配列の中で、子孫に対応する区間内での最小値がその水が移動するときのクエリのインデックスとなる(同時に行く頂点の番号も分かる)

● 愚直にやると O(NM)

!! Segment Tree !!

どうやって求めるか (3)

● セグツリーで高速化する● 次に行くクエリのインデックスが求まる● 最終的に行く頂点は、次のクエリから最終的

に行く頂点● 次に行く場所がないクエリに対応する頂点に

集まるので、その頂点にクエリ 2 の水量を足せば良い

● こうして UnionFind 的に求めることができる

1 2 3 4 5 6 7 8

(各頂点は先程の例でのクエリを表す)

対応する頂点:

1 2 4 2 6 5 1 7

+10

+5

+3

余談

● クエリから次に行くクエリに辺を張ると、クエリたちからなる木ができる

● よってクエリ 1 で集まる水量は子孫のクエリ2 の x の和になるので、最後の水量じゃなくそれぞれのクエリ 1 で集まった水量でも求められた

● ということに気づいたのはコンテスト中で、もう遅かった

● Submissions : 12● Accepted : 3 ● First Accept : anta