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
120
数列をプレゼントに / yukicoder-no-332
camypaper
0
160
DSU on Tree
camypaper
0
4.1k
五輪ピック / yukicoder-no-408
camypaper
0
210
Featured
See All Featured
Context Engineering - Making Every Token Count
addyosmani
6
250
Agile that works and the tools we love
rasmusluckow
331
21k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
9
870
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
132
19k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
46
7.7k
The Straight Up "How To Draw Better" Workshop
denniskardys
238
140k
GitHub's CSS Performance
jonrohan
1032
470k
Rebuilding a faster, lazier Slack
samanthasiow
84
9.2k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
How GitHub (no longer) Works
holman
315
140k
Producing Creativity
orderedlist
PRO
347
40k
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.