Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
部分永続 Union Find / persistent_dsu
Search
camypaper
November 07, 2017
1
3.6k
部分永続 Union Find / persistent_dsu
camypaper
November 07, 2017
Tweet
Share
More Decks by camypaper
See All by camypaper
門松と魔法(2) 解説 / yukicoder-no-284
camypaper
0
130
数列をプレゼントに / yukicoder-no-332
camypaper
0
160
DSU on Tree
camypaper
0
4.2k
五輪ピック / yukicoder-no-408
camypaper
0
220
Featured
See All Featured
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.5k
The Cost Of JavaScript in 2023
addyosmani
55
9.3k
YesSQL, Process and Tooling at Scale
rocio
174
15k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
3.8k
It's Worth the Effort
3n
187
29k
Designing for humans not robots
tammielis
254
26k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Embracing the Ebb and Flow
colly
88
4.9k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
Principles of Awesome APIs and How to Build Them.
keavy
127
17k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
10
680
A Tale of Four Properties
chriscoyier
162
23k
Transcript
部分永続Union Find camypaper
問題1 • N 頂点の無向グラフがある • Q 個のクエリを処理せよ – u, v
をつなぐ辺を追加 – u, v が同じ連結成分に含まれるか判定 • Union Findするだけ
問題2 • N 頂点の無向グラフがある • Q 個のクエリを処理せよ – u, v
をつなぐ辺を追加 – i 番目のクエリを処理した時点において u, v が同じ連結成分に含まれるか判定 • クエリ先読みして,Union Findするだけ
問題3(本題) • N 頂点の無向グラフがある • Q 個のクエリをオンラインで処理せよ – u, v
をつなぐ辺を追加 – i 番目のクエリを処理した時点において u, v が同じ連結成分に含まれるか判定 • クエリ先読みできない… • どうする?
部分永続Union Find
機能 • unite(u, v) – 頂点 u, v が含まれる連結成分を連結する •
find(u, t) – t 番目のクエリを処理した時点における 頂点 u が含まれる連結成分の根を求める • Union Findの実装はrankによる unite: O(logN), find: O(logN) のやつを ベースにすることにする(経路圧縮なし)
実装(1)全部愚直に持つ • 表のi 行 j 列目は,i 番目のクエリを処理し た時点での,頂点 j の親を表す
頂点番号 1 2 3 4 5 クエリ番号 0 1 2 3 4 5 1 ??? ??? ??? ??? ??? 2 ??? ??? ??? ??? ??? 3 ??? ??? ??? ??? ??? 4 ??? ??? ??? ??? ??? 5 ??? ??? ??? ??? ???
実装(1)全部愚直に持つ • 0番目のクエリ: 初期状態 頂点番号 1 2 3 4 5
クエリ番号 0 1 2 3 4 5 1 ??? ??? ??? ??? ??? 2 ??? ??? ??? ??? ??? 3 ??? ??? ??? ??? ??? 4 ??? ??? ??? ??? ??? 5 ??? ??? ??? ??? ???
実装(1)全部愚直に持つ • 1番目のクエリ: 1, 3 をつなぐ 頂点番号 1 2 3
4 5 クエリ番号 0 1 2 3 4 5 1 1 2 1 4 5 2 ??? ??? ??? ??? ??? 3 ??? ??? ??? ??? ??? 4 ??? ??? ??? ??? ??? 5 ??? ??? ??? ??? ???
実装(1)全部愚直に持つ • 2番目のクエリ: 3, 5 をつなぐ 頂点番号 1 2 3
4 5 クエリ番号 0 1 2 3 4 5 1 1 2 1 4 5 2 1 2 1 4 1 3 ??? ??? ??? ??? ??? 4 ??? ??? ??? ??? ??? 5 ??? ??? ??? ??? ???
実装(1)全部愚直に持つ • 3番目のクエリ: 1, 5 をつなぐ 頂点番号 1 2 3
4 5 クエリ番号 0 1 2 3 4 5 1 1 2 1 4 5 2 1 2 1 4 1 3 1 2 1 4 1 4 ??? ??? ??? ??? ??? 5 ??? ??? ??? ??? ???
実装(1)全部愚直に持つ • 4番目のクエリ: 2, 4 をつなぐ 頂点番号 1 2 3
4 5 クエリ番号 0 1 2 3 4 5 1 1 2 1 4 5 2 1 2 1 4 1 3 1 2 1 4 1 4 1 2 1 2 1 5 ??? ??? ??? ??? ???
実装(1)全部愚直に持つ • 5番目のクエリ: 4, 5 をつなぐ 頂点番号 1 2 3
4 5 クエリ番号 0 1 2 3 4 5 1 1 2 1 4 5 2 1 2 1 4 1 3 1 2 1 4 1 4 1 2 1 2 1 5 1 1 1 2 1
実装(1)まとめ • この表の行にそってfindをすればO(logN)で findができる! • 空間 O(NQ) は使い物にならない 頂点番号 1
2 3 4 5 クエリ番号 0 1 2 3 4 5 1 1 2 1 4 5 2 1 2 1 4 1 3 1 2 1 4 1 4 1 2 1 2 1 5 1 1 1 2 1
実装(2)使ったところだけ記録 • 0番目のクエリ: 初期状態 頂点番号 1 2 3 4 5
クエリ番号 0 1 2 3 4 5 1 ??? ??? ??? ??? ??? 2 ??? ??? ??? ??? ??? 3 ??? ??? ??? ??? ??? 4 ??? ??? ??? ??? ??? 5 ??? ??? ??? ??? ???
実装(2)使ったところだけ記録 • 1番目のクエリ: 1, 3 をつなぐ 頂点番号 1 2 3
4 5 クエリ番号 0 1 2 3 4 5 1 1 1 2 ??? ??? ??? ??? ??? 3 ??? ??? ??? ??? ??? 4 ??? ??? ??? ??? ??? 5 ??? ??? ??? ??? ???
実装(2)使ったところだけ記録 • 2番目のクエリ: 3, 5 をつなぐ 頂点番号 1 2 3
4 5 クエリ番号 0 1 2 3 4 5 1 1 1 2 1 1 3 ??? ??? ??? ??? ??? 4 ??? ??? ??? ??? ??? 5 ??? ??? ??? ??? ???
実装(2)使ったところだけ記録 • 3番目のクエリ: 1, 5 をつなぐ 頂点番号 1 2 3
4 5 クエリ番号 0 1 2 3 4 5 1 1 1 2 1 1 3 4 ??? ??? ??? ??? ??? 5 ??? ??? ??? ??? ???
実装(2)使ったところだけ記録 • 4番目のクエリ: 2, 4 をつなぐ 頂点番号 1 2 3
4 5 クエリ番号 0 1 2 3 4 5 1 1 1 2 1 1 3 4 2 2 5 ??? ??? ??? ??? ???
実装(2)使ったところだけ記録 • 5番目のクエリ: 4, 5 をつなぐ 頂点番号 1 2 3
4 5 クエリ番号 0 1 2 3 4 5 1 1 1 2 1 1 3 4 2 2 5 1 1
表をぐっとにらむと • 1番目のクエリ以降,各クエリにつき 定数個の要素しか更新しない – 経路圧縮なしのUnion Findだから当たり前 頂点番号 1 2
3 4 5 クエリ番号 0 1 2 3 4 5 1 1 1 2 1 1 3 4 2 2 5 1 1
表をぐっとにらむと • 一度でも連結成分の親でなくなった頂点 は二度と連結時に親にならない – 表の赤以降の時点で親になることはない 頂点番号 1 2 3
4 5 クエリ番号 0 1 2 3 4 5 1 1 1 2 1 1 3 4 2 2 5 1 1
Find(u, t): O(logN) • find(u, t)について以下のように動作させる – u が時刻 t
以降において,親でないとき • find(u の親, t) を返す – そうでないとき • u を返す 頂点番号 1 2 3 4 5 クエリ番号 0 1 2 3 4 5 1 1 1 2 1 1 3 4 2 2 5 1 1
Find(u, t): O(logN) • find(u, t)について以下のように動作させる – u が時刻 t
以降において,親でないとき • find(u の親, t) を返す – そうでないとき • u を返す 頂点番号 1 2 3 4 5 クエリ番号 0 1 2 3 4 5 1 1 1 2 1 1 3 4 2 2 5 1 1 これは,各列の末尾 (黃セル)だけ見ればOK O(1)で判定可能 rankベースのUnion Find なのでO(logN)回しか 呼ばれない
Find(u, t): O(logN) • find(u, t)について以下のように動作させる – u が時刻 t
以降において,親でないとき • find(u の親, t) を返す – そうでないとき • u を返す • 例: find(4, 4) – 時刻 4において 親でない – find(2, 4) • 時刻4において親 これは,各列の末尾 (黃セル)だけ見ればOK O(1)で判定可能 頂点番号 1 2 3 4 5 クエリ番号 0 1 2 3 4 5 1 1 1 2 1 1 3 4 2 2 5 1 1 rankベースのUnion Find なのでO(logN)回しか 呼ばれない
Unite(u, v): O(logN) • i 番目のクエリの時点で – find(u, i), find(v,
i) して根を探す – rank実装のUnion Findの要領で表を埋める • find部分が一番重くO(logN) 頂点番号 1 2 3 4 5 クエリ番号 0 1 2 3 4 5 1 1 1 2 1 1 3 4 2 2 5 ??? ??? ??? ??? ???
実装(2) まとめ • 更新されたところだけ覚えておけばいい • find: O(logN), unite: O(logN)が実現できた
応用編
問題4 • N 頂点の無向グラフがある • Q 個のクエリをオンラインで処理せよ – u, v
をつなぐ辺を追加 – i 番目のクエリを処理した時点における u を含む連結成分のサイズを出力
機能 • unite(u, v) – 頂点 u, v が含まれる連結成分を連結する •
find(u, t) – t 番目のクエリを処理した時点における 頂点 u が含まれる連結成分の根を求める • size(u, t) – t 番目のクエリを処理した時点における 頂点 u が含まれる連結成分のサイズを求める
実装 • 表で持つ情報をちょっと変える – 今まで:親の番号だけ持たせていた 頂点番号 1 2 3 4
5 クエリ番号 0 1 1 1 1 1 1 2 1 2 3 1 3 4 2 2 5 5 1 頂点番号 1 2 3 4 5 クエリ番号 0 1 2 3 4 5 1 1 1 2 1 1 3 4 2 2 5 1 1
実装 • 表で持つ情報をちょっと変える – 緑字: 連結成分のサイズ – 赤字:親である頂点の番号 頂点番号 1
2 3 4 5 クエリ番号 0 1 1 1 1 1 1 2 1 2 3 1 3 4 2 2 5 5 1
Find(u, t): O(logN) • find(u, t)について以下のように動作させる – u が時刻 t
以降において,親でないとき • find(u の親, t) を返す – そうでないとき • u を返す 頂点番号 1 2 3 4 5 クエリ番号 0 1 1 1 1 1 1 2 1 2 3 1 3 4 2 2 5 5 1
Find(u, t): O(logN) • find(u, t)について以下のように動作させる – u が時刻 t
以降において,親でないとき • find(u の親, t) を返す – そうでないとき • u を返す これは,各列の末尾 (黃セル)だけ見ればOK O(1)で判定可能 頂点番号 1 2 3 4 5 クエリ番号 0 1 1 1 1 1 1 2 1 2 3 1 3 4 2 2 5 5 1 rankベースのUnion Find なのでO(logN)回しか 呼ばれない
• find(u, t)について以下のように動作させる – u が時刻 t 以降において,親でないとき • find(u
の親, t) を返す – そうでないとき • u を返す • 例: find(4, 4) – 時刻 4において 親でない – find(2, 4) • 時刻4において親 頂点番号 1 2 3 4 5 クエリ番号 0 1 1 1 1 1 1 2 1 2 3 1 3 4 2 2 5 5 1 Find(u, t): O(logN) これは,各列の末尾 (黃セル)だけ見ればOK O(1)で判定可能 rankベースのUnion Find なのでO(logN)回しか 呼ばれない
• size(u, t)について以下のように動作させる – find(u, t)して根 v を探す – v
について,時刻 t 以前における連結成分の サイズが保存された位置を二分探索で求める • 例: size(4, 4) – 親 v は頂点 2 頂点番号 1 2 3 4 5 クエリ番号 0 1 1 1 1 1 1 2 1 2 3 1 3 4 2 2 5 5 1 Size(u, t): O(logN)
• size(u, t)について以下のように動作させる – find(u, t)して根 v を探す – v
について,時刻 t 以前における連結成分の サイズが保存された位置を二分探索で求める • 例: size(4, 4) – 親 v は頂点 2 – 二分探索すると 時刻4でサイズが 2になったことが わかる 頂点番号 1 2 3 4 5 クエリ番号 0 1 1 1 1 1 1 2 1 2 3 1 3 4 2 2 5 5 1 Size(u, t): O(logN)
• size(u, t)について以下のように動作させる – find(u, t)して根 v を探す – v
について,時刻 t 以前における連結成分の サイズが保存された位置を二分探索で求める • 例: size(4, 4) – 親 v は頂点 2 – 二分探索すると 時刻4でサイズが 2になったことが わかる 頂点番号 1 2 3 4 5 クエリ番号 0 1 1 1 1 1 1 2 1 2 3 1 3 4 2 2 5 5 1 Size(u, t): O(logN) find(u, t)はO(logN) 1回の二分探索でO(logN)
Unite(u, v): O(logN) • i 番目のクエリの時点で – find(u, i), find(v,
i) して根を探す – rank実装のUnion Findの要領で表を埋める – 新しい親は連結成分のサイズを,子側は 親の番号を記録 頂点番号 1 2 3 4 5 クエリ番号 0 1 1 1 1 1 1 2 1 2 3 1 3 4 2 2 5 ??? ??? ??? ??? ???
まとめ • find, size, uniteがいずれも O(logN) で可能な 部分永続Union Findができた –
(必ずしも同じように実装しなくても達成可能)
解ける問題 • AGC002 D: Stamp Rally • yukicoder No. 416:
旅行会社 • CodeFesitival 2016 Elimination Tournament Round 1 A: グラフ • etc.