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.4k
部分永続 Union Find / persistent_dsu
camypaper
November 07, 2017
Tweet
Share
More Decks by camypaper
See All by camypaper
門松と魔法(2) 解説 / yukicoder-no-284
camypaper
0
100
数列をプレゼントに / yukicoder-no-332
camypaper
0
150
DSU on Tree
camypaper
0
3.7k
五輪ピック / yukicoder-no-408
camypaper
0
190
Featured
See All Featured
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
506
140k
Faster Mobile Websites
deanohume
305
30k
Bootstrapping a Software Product
garrettdimon
PRO
305
110k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
226
22k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
8
900
Making Projects Easy
brettharned
115
5.9k
Facilitating Awesome Meetings
lara
50
6.1k
Agile that works and the tools we love
rasmusluckow
327
21k
Rebuilding a faster, lazier Slack
samanthasiow
79
8.7k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
28
9.1k
Keith and Marios Guide to Fast Websites
keithpitt
409
22k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
44
6.8k
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.