Successfully reported this slideshow.                                  Upcoming SlideShare
×

# LCA and RMQ ~簡潔もあるよ！~

7,631 views

Published on

LCAとRMQの関係とそれを利用した高速なアルゴリズム、簡潔データ構造化の大雑把な解説。

Published in: Science
• Full Name
Comment goes here.

Are you sure you want to Yes No Are you sure you want to  Yes  No
• Dating for everyone is here: ♥♥♥ http://bit.ly/39sFWPG ♥♥♥

Are you sure you want to  Yes  No

Are you sure you want to  Yes  No

Are you sure you want to  Yes  No

Are you sure you want to  Yes  No

### LCA and RMQ ~簡潔もあるよ！~

1. 1. ERATO若手輪読会 2014/11/19 LCA and RMQ 北海道大学大学院 情報科学研究科 博士1年 井上 祐馬 1
2. 2. ERATO若手輪読会 2014/11/19 • LCA: Lowest Common Ancestor (最近共通祖先) • 根付き木 T 上の2頂点 u, v に対するクエリ LCA(u,v) • u と v の祖先であって、もっとも深い頂点 x を返す • RMQ: Range Minimum Query (区間最小値) • 列 A[1:n] 上の区間 [l, r] に対するクエリ RMQ(l,r) • A[l:r] 中での最小値 A[i] を取るような i を返す • LCA と RMQ には密接な関係がある LCAとRMQ 2 u v x id 1 2 3 4 5 6 A[id] 1 8 2 6 3 5 l r i T
3. 3. ERATO若手輪読会 2014/11/19 LCAとRMQ • クエリ処理アルゴリズムの計算量表記: <f(n), g(n)> • f(n): 前処理時間, g(n): 1つのクエリの処理時間 3 ・LCA と RMQ を <O(n), O(1)> で解く ・(時間があれば)空間 2n + o(n) bit の  簡潔データ構造で <O(n), O(1)> で処理する 今日の目標
4. 4. ERATO若手輪読会 2014/11/19 LCAとRMQ • クエリ処理アルゴリズムの計算量表記: <f(n), g(n)> • f(n): 前処理時間, g(n): 1つのクエリの処理時間 4 LCA を <f(n), g(n)> で解くアルゴリズムが存在  → RMQ は <f(n)+O(n), g(n)+O(1)> で解ける RMQ を <f(n), g(n)> で解くアルゴリズムが存在  → LCA は <O(f(n))+O(n), O(g(n))+O(1)> で解ける 定理1 定理2
5. 5. ERATO若手輪読会 2014/11/19 RMQ to LCA 5 LCA を <f(n), g(n)> で解くアルゴリズムが存在  → RMQは <f(n)+O(n), g(n)+O(1)> で解ける 定理1 • 列Aを Cartesian Tree に変換 • Cartesian Tree • 値の2分ヒープ構造 • 頂点ラベルはインデックス • 子の左右が列の左右と一致 id 1 2 3 4 5 6 A[id] 1 8 2 6 3 5 1 3 2 5 4 6
6. 6. ERATO若手輪読会 2014/11/19 RMQ to LCA 6 • RMQ(l,r):  Cartesian Tree上でLCA(l,r)を解く ことで最小値インデックスが求まる  • Cartesian Treeの構築: O(n) • 最小値そのものが知りたいとき:  メモリアクセス O(1) id 1 2 3 4 5 6 A[id] 1 8 2 6 3 5 1 3 2 5 4 6 LCA を <f(n), g(n)> で解くアルゴリズムが存在  → RMQは <f(n)+O(n), g(n)+O(1)> で解ける 定理1
7. 7. ERATO若手輪読会 2014/11/19 LCA to RMQ • 木 T を Euler Tour で展開 • Euler Tour: • TをDFSで辿る • 頂点の訪問順で列を定義 • 列の長さは必ず2n-1 7 RMQ を <f(n), g(n)> で解くアルゴリズムが存在  → LCA は <O(f(n))+O(n), O(g(n))+O(1)> で解ける 定理2 4 65 2 1 3 T id 1 2 3 4 5 6 7 8 9 10 11 A[id] 1 2 1 3 4 3 5 3 6 3 1
8. 8. ERATO若手輪読会 2014/11/19 LCA to RMQ • LCA(u,v):  深さ配列d上でRMQ(l,r)  (l, rはu, vのAでの出現位置) • Euler Tourへの展開: O(n) • LCAの頂点番号取得:   メモリアクセス O(1) 8 RMQ を <f(n), g(n)> で解くアルゴリズムが存在  → LCA は <O(f(n))+O(n), O(g(n))+O(1)> で解ける 定理2 4 65 2 1 3 T id 1 2 3 4 5 6 7 8 9 10 11 A[id] 1 2 1 3 4 3 5 3 6 3 1 d[id] 0 1 0 1 2 1 2 1 2 1 0
9. 9. ERATO若手輪読会 2014/11/19 LCAとRMQ • 定理より、LCA または RMQ のどちらか一方が <O(n), O(1)> で解ければ、もう一方も<O(n), O(1)> • LCAとRMQには、それぞれ様々なアルゴリズムが 提案されている 9
10. 10. ERATO若手輪読会 2014/11/19 RMQのアルゴリズム 10 空間 前処理 クエリ Segment Tree (動的) O(n) O(n) O(log n) Sparse Table O(n logn) O(n logn) O(1) Cartesian Tree + LCA O(n) + ? O(n) + ? O(1) + ? ※ここでは各値を表すのに必要な O(logn) は無視
11. 11. ERATO若手輪読会 2014/11/19 LCAのアルゴリズム 11 空間 前処理 クエリ Doubling O(n logn) O(n logn) O(log n) Heavy Path Decomposition O(n) O(n) O(1) Euler Tour + RMQ O(n) + ? O(n) + ? O(1) + ? ※ここでは各値を表すのに必要な O(logn) は無視
12. 12. ERATO若手輪読会 2014/11/19 <O(n), O(1)>アルゴリズム • LCAはHeavy Path Decompositionを利用して、 直接 <O(n), O(1)> で解くことが可能 • ただし、簡潔化が難しい • LCAで必要とされるRMQがある特殊な条件を満た すことを利用して、RMQを <O(n), O(1)> で解く 12
13. 13. ERATO若手輪読会 2014/11/19 1RMQ • LCA: Euler Tour の深さ配列でRMQ • 1回の移動で深さはちょうど1だけ変わる • 深さ配列の隣接要素同士は+1 か -1 だけ異なる • 隣接要素の変化が 1 である列上での RMQ を 1RMQ と呼ぶ • 1RMQ が <O(n), O(1)> で解ければ、LCA も <O(n), O(1)> で解ける 134 65 2 1 3 id 1 2 3 4 5 6 7 8 9 10 11 A[id] 1 2 1 3 4 3 5 3 6 3 1 d[id] 0 1 0 1 2 1 2 1 2 1 0 +1 +1 +1 +1 +1 -1 -1-1-1-1
14. 14. ERATO若手輪読会 2014/11/19 <O(n), O(1)> RMQ RMQを <O(n), O(1)> で解く流れ 1. RMQ を Cartesian Tree に変換し、LCA に帰着  ( 時間・空間: O(n) ) 2. LCA を Euler Tour で展開し、 1RMQ に帰着  ( 時間・空間: O(n) ) 3. 1RMQ を以下のテクニックで <O(n), O(1)> で解く • ブロック分割 • Sparse Table • Table Lookup 14 [Bender et. al. '05]
15. 15. ERATO若手輪読会 2014/11/19 ブロック分割 • 簡潔データ構造の典型テクニック • 長さnの列を長さs = logn/2のブロックに分割 • ブロックの数 B = 2n/logn • 各ブロックの最小値インデックスを O(n) で前計算 • 全体の RMQ クエリは、以下のクエリに分割される • ブロックの区間に対する RMQ クエリ1回 • ブロック内部に対する RMQ クエリ2回 15 id 1 2 3 4 5 6 7 8 9 101112131415161718192021222324252627282930 A[id] 1 2 1 3 4 3 5 3 6 3 1 8 4 9 11 4 1 5 6 3 2 5 2 5 2 1 9 8 4 1
16. 16. ERATO若手輪読会 2014/11/19 ブロック分割 • 簡潔データ構造の典型テクニック • 長さnの列を長さs = logn/2のブロックに分割 • ブロックの数 B = 2n/logn • 各ブロックの最小値インデックスを O(n) で前計算 • 全体の RMQ クエリは、以下のクエリに分割される • ブロックの区間に対する RMQ = Sparse Table • ブロック内部に対する RMQ = Table Lookup 16 id 1 2 3 4 5 6 7 8 9 101112131415161718192021222324252627282930 A[id] 1 2 1 3 4 3 5 3 6 3 1 8 4 9 11 4 1 5 6 3 2 5 2 5 2 1 9 8 4 1 それぞれ <O(n), O(1)> で 解ければOK
17. 17. ERATO若手輪読会 2014/11/19 Sparse Table • i 番目から長さ2kの区間の最小値インデックスをそれ ぞれ記憶したO(n logn)のテーブルを持つ • 構築: O(n logn) • S[i][k+1] = argmin( A[S[i][k]], A[S[i+2k][k]] ) • クエリ: O(1) • RMQ(i, j) = argmin( A[S[i][k]], A[S[j-2k+1][k]] ) • k = ﬂoor( log(j-i) ) ← O(1)で求められると仮定 17 id 1 2 3 4 5 6 7 8 A[id] 1 2 1 3 4 3 5 3 id 1 2 3 4 5 6 7 8 A[id] 1 2 1 3 4 3 5 3 構築: クエリ:
18. 18. ERATO若手輪読会 2014/11/19 Sparse Table • i 番目から長さ2kの区間の最小値インデックスをそれ ぞれ記憶したO(n logn)のテーブルを持つ • B個のブロックに対し、<O(B logB), O(1)> のアルゴ リズム • B = 2n/lognより、  B logB = 2n/logn・(log2n - loglogn) = O(n) 18 id 1 2 3 4 5 6 7 8 A[id] 1 2 1 3 4 3 5 3 id 1 2 3 4 5 6 7 8 A[id] 1 2 1 3 4 3 5 3 構築: クエリ:
19. 19. ERATO若手輪読会 2014/11/19 Table Lookup • 簡潔データ構造の典型テクニック その2 • 1 で変化している列の最小値インデックスは、値 そのものを見なくても変化量だけ見ればわかる • すべての変化パターンと区間 [l,r]について、最小値 インデックスを記録して参照すればよい • 長さ s の列の変化のパターンは2s通り • よって、<O(s22s), O(1)> のアルゴリズム • s = logn/2より、s22s = O(log2n n) = o(n) 19
20. 20. ERATO若手輪読会 2014/11/19 <O(n), O(1)> RMQ RMQ を <O(n), O(1)> で解けた！！！ 1. RMQ を Cartesian Tree に変換し、LCA に帰着  ( 時間・空間: O(n) ) 2. LCA を Euler Tour で展開し、 1RMQ に帰着  ( 時間・空間: O(n) ) 3. 1RMQ を以下のテクニックで <O(n), O(1)> で解く • ブロック分割 • Sparse Table • Table Lookup 20 [Bender et. al. '05]
21. 21. ERATO若手輪読会 2014/11/19 -----↓ここから簡潔↓----- 21
22. 22. ERATO若手輪読会 2014/11/19 簡潔RMQ RMQ を <O(n), O(1)> で解けた！！！ 1. RMQ を Cartesian Tree に変換し、LCA に帰着  ( 時間・空間: O(n) ) 2. LCA を Euler Tour で展開し、 1RMQ に帰着  ( 時間・空間: O(n) ) 3. 1RMQ を以下のテクニックで <O(n), O(1)> で解く • ブロック分割 • Sparse Table • Table Lookup 22 BP (Balanced Parentheses) 表現で2n bitに BP上の rank( - rank) が深さに対応 → Euler Tour なしに 1RMQ 分割を多段にすることで o(n) bitに [Sadakane '07]
23. 23. ERATO若手輪読会 2014/11/19 簡潔RMQ • 問題点: BP 上でわかるのは pre-order  RMQ で求めたいインデックスは  Cartesian tree 上では in-order • 対応を覚える場合O(n logn) bit を使う → not 簡潔 • Cartesian Tree に dummy node を n 個付加するこ とで解決 → 4n + o(n) bitに 23 [Sadakane '07] id 1 2 3 4 5 6 A[id] 1 8 2 6 3 5 1 3 2 5 4 6 ( ( ( ) ( ( ) ( ) ) ) 1 1 3 2 2 8 4 6 5 3 6 5
24. 24. ERATO若手輪読会 2014/11/19 簡潔RMQ • 問題点: BP 上でわかるのは pre-order  RMQ で求めたいインデックスは  Cartesian tree 上では in-order • 対応を覚える場合O(n logn) bit を使う → not 簡潔 • Cartesian Tree に dummy node を n 個付加するこ とで解決 → 4n + o(n) bitに 24 [Sadakane '07] id 1 2 3 4 5 6 A[id] 1 8 2 6 3 5 1 3 2 5 4 6 ( ( ( ) ( ( ) ( ) ) ) 1 1 3 2 2 8 4 6 5 3 6 5 2n にしたい
25. 25. ERATO若手輪読会 2014/11/19 簡潔RMQ • Cartesian Tree + BP の代わりに 2D-Min Heap + DFUDS (Depth-First Unary Degree Sequence) • 流れ: • 入力列を 2D-Min Heap を表すDFUDSに変換 • O(n)時間、 DFUDSは 2n bit • DFUDS に必要な索引を付加 • O(n)時間、索引は o(n) bit • 索引付き DFUDS 上で LCAを解く • 内部で rank, select, ﬁndopen, 1RMQ 等を使用 • O(1) 時間 25 [Fischer '09] id 0 1 2 3 4 5 6 A[id] - 1 8 2 6 3 5 1 32 54 6 2D-Min Heap 0 DFUDS: ( ( ) ( ( ) ) ( ( ) ) ( ) )
26. 26. ERATO若手輪読会 2014/11/19 簡潔RMQ • Cartesian Tree + BP の代わりに 2D-Min Heap + DFUDS (Depth-First Unary Degree Sequence) • 2D-Min Heap: • 自分より左かつ小さいもののうち、最も右にある ものを親にする 26 [Fischer '09] id 0 1 2 3 4 5 6 A[id ] - 1 8 2 6 3 5 1 3 2 5 4 6 1 32 54 6 Cartesian Tree 2D-Min Heap 0
27. 27. ERATO若手輪読会 2014/11/19 簡潔RMQ • RMQ(i, j)は、2D-Min Heap 上では、 • LCA(i, j)が i → RMQ(i, j) = i • それ以外 → RMQ(i, j) = LCA(i, j)の子で、jの先祖 27 [Fischer '09] id 0 1 2 3 4 5 6 A[id ] - 1 8 2 6 3 5 2D-Min Heap 1 32 54 6 0 i j LCA(2,4) RMQ(2,4)
28. 28. ERATO若手輪読会 2014/11/19 簡潔RMQ • Cartesian Tree + BP の代わりに 2D-Min Heap + DFUDS (Depth-First Unary Degree Sequence) • DFUDS: • 葉は ( ) • w 個の子 T1, ..., Tw の親は w+1 個の ( と 1個の ) の後、 子を続ける．ただし、子の表現は先頭の ( を1つ削る 28 [Fischer '09] ( ( ) ( ( ) ) ( ( ) ) ( ) ) id 0 1 2 3 4 5 6 d 1 2 1 2 3 2 3 4 3 4 3 2 1 0 A[id] - 1 8 2 6 3 5 1 32 54 6 0
29. 29. ERATO若手輪読会 2014/11/19 • RMQ(i, j) 1. l ← select)(U, i+1), r ← select)(U, j) 2. w = 1RMQ(l, r) 3. if rank)(U, ﬁndopen(U, w)) = i, then return i 4. else rank)(U, w) 29 簡潔RMQ [Fischer '09] U: ( ( ) ( ( ) ) ( ( ) ) ( ) ) id 0 1 2 3 4 5 6 d 1 2 1 2 3 2 1 2 3 2 1 2 1 0 A[id] - 1 8 2 6 3 5 1 32 54 6 0 i j l r 1RMQ(l,r) ﬁndopen
30. 30. ERATO若手輪読会 2014/11/19 • RMQ(i, j) 1. l ← select)(U, i+1), r ← select)(U, j) 2. w = 1RMQ(l, r) 3. if rank)(U, ﬁndopen(U, w)) = i, then return i 4. else rank)(U, w) 30 簡潔RMQ [Fischer '09] U: ( ( ) ( ( ) ) ( ( ) ) ( ) ) id 0 1 2 3 4 5 6 d 1 2 1 2 3 2 1 2 3 2 1 2 1 0 A[id] - 1 8 2 6 3 5 1 32 54 6 0 i j l r 1RMQ(l,r) ﬁndopen DFUDS 上の RMQ では、 w は i と j のLCAの子であり、 jの祖先である (ただし LCA が iのとき w=i ) [Jansson et. al. '07]
31. 31. ERATO若手輪読会 2014/11/19 • RMQ(i, j) 1. l ← select)(U, i+1), r ← select)(U, j) 2. w = 1RMQ(l, r) 3. if rank)(U, ﬁndopen(U, w)) = i, then return i 4. else rank)(U, w) 31 簡潔RMQ [Fischer '09] U: ( ( ) ( ( ) ) ( ( ) ) ( ) ) id 0 1 2 3 4 5 6 d 1 2 1 2 3 2 1 2 3 2 1 2 1 0 A[id] - 1 8 2 6 3 5 1 32 54 6 0 i j l r 1RMQ(l,r) ﬁndopen 親が preorder わかる
32. 32. ERATO若手輪読会 2014/11/19 • RMQ(i, j) 1. l ← select)(U, i+1), r ← select)(U, j) 2. w = 1RMQ(l, r) 3. if rank)(U, ﬁndopen(U, w)) = i, then return i 4. else rank)(U, w) 32 簡潔RMQ [Fischer '09] U: ( ( ) ( ( ) ) ( ( ) ) ( ) ) id 0 1 2 3 4 5 6 d 1 2 1 2 3 2 1 2 3 2 1 2 1 0 A[id] - 1 8 2 6 3 5 1 32 54 6 0 i j l r 1RMQ(l,r) ﬁndopen自分の preorder わかる
33. 33. ERATO若手輪読会 2014/11/19 割愛したところ • 入力列から直接 2n bit のDFUDSへ O(n) で変換 • 簡潔でない方法: スタックを利用したアルゴリズム • 簡潔な方法: スタックを簡潔にする • 1RMQ をより簡潔に • o(n) で隠された部分がより succinct に • 具体的には、(loglogn)2 かかっていたところが loglogn に落とせる 33
34. 34. ERATO若手輪読会 2014/11/19 まとめ • LCA と RMQは適切に変換することで等価な問題 として解ける • LCA to RMQ: Euler Tour, BP, DFUDS • RMQ to LCA: Cartesian Tree, 2D-Min Heap • LCA で要求される RMQ が 1RMQ であることを 利用し、<O(n), O(1)> を実現する • 木の簡潔表現と LCA, RMQ の簡潔辞書により、 2n + o(n) bitで、<O(n), O(1)> を実現する 34