-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrange_minimum_query.html
85 lines (83 loc) · 4.7 KB
/
range_minimum_query.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<title>Range Minimum Query</title>
<p>
<b>range minimum query</b>(<b>RMQ</b>)とは、整列集合の列上で区間内の最小値を求めるという問題である。最小値の場所を求めるというバリエーションもある。
</p><p>
<a href='lowest_common_ancestor'>lowest common ancestor</a>と深い関係があり、両者を還元することができ、解くのにも使われる。
クエリ問題版では、lowest common ancestorに還元する前処理$Θ(n)$, クエリ$Θ(1)$のアルゴリズムが存在する。
</p>
<h2>定義</h2>
<p>
整列集合の列$A$と、区間を表す2つの整数$0 \le l \le r \lt |A|$に対して、
$$
RMQ_{A}(l, r) = \min_{a \in A[l,r]} a
$$
を$A,l,r$の区間最小値といい、それを求める問題をrange minimum queryという。
</p>
<h3>クエリ問題</h3>
<p>
列が事前に与えられる。
クエリでは区間が与えられて入力のRMQを求める。
</p>
<h3>動的問題</h3>
<p>
列に対して初期状態を求める。
RMQクエリでは内部状態と区間が与えられて入力のRMQを求める。
</p>
<h3>パラメータ</h3>
<ul>
<li>$n = |A|$</li>
</ul>
<h2>自明な還元</h2>
<h3>最大値を求める</h3>
<p>要素の順序を反転させれば良い。</p>
<h3>最小値の位置を求める</h3>
<p>列を$A' = zip(A, [0 \cdots])$とし、順序を辞書式順序にすれば位置も一緒に求めることができる。</p>
<h2>アルゴリズム</h2>
<h3>segment tree</h3>
<p>
"segment tree"を用いると、要素の変更クエリなどに対応した動的問題版を$Θ(\log n)$で解くことができる。
</p><p>
クエリ問題版にも適用でき、その場合、前計算$Θ(n)$時間, $Θ(n)$空間, クエリ$Θ(\log n)$時間を達成する。
</p>
<h3>平衡探索木</h3>
<p>"平衡探索木"を用いると、区間の移動や反転などさらなる操作に対応でき、クエリ$Θ(\log n)$時間を達成する。</p>
<h3>sparse table</h3>
<p>
<b>sparse table</b>(ST)では、全ての区間$A[l,l + 2^k - 1]$の最小値を事前計算する。
この事前計算は動的計画法により計算できる。
クエリでは、入力区間を被覆しかつはみ出さないように、2つの事前計算した区間を撰ぶ。これには$\log_2 (r-l+1)$の計算が必要になるが、これは事前計算しておけばよい。
</p><p>
クエリ問題版を、前計算$Θ(n \log n)$時間, $Θ(n \log n)$空間, クエリ$Θ(1)$時間で解くことができる。
</p>
<h3>lowest common ancestorへの還元</h3>
<p>
"Cartesian tree"という根付き木に入力を変換することでlowest common ancestor問題へと還元できる。詳細は"Cartesian tree"を参照。
</p><p>
クエリ問題版で前計算$Θ(n)$時間, $Θ(n)$空間, クエリ$Θ(1)$時間を達成する。
</p>
<h2 id='plusminus-rmq' >±RMQ</h2>
<p>
<b>±RMQ</b> (± range minimum query)とは、整数列のRMQであって、「隣接する要素の差が±1」という条件をつけたものである。
</p>
<p>
最小値の位置を求めるように拡張できる。この場合、位置は関係なく隣接する実際の要素の差が±1という条件となる。
</p><p>
lowest common ancestorは区間最小値の位置を求めるように拡張された±RMQに還元することができる。
</p>
<h3>±RMQアルゴリズム</h3>
<p>
±1であるという条件を用いて"#Sparse Table"に拡張を加えて高速化できる。
</p><p>
入力を$\frac{\log n}{1 + \epsilon}$のサイズのブロックへ分割する。
そのブロックを1要素と考えてsparse tableを適用する。これは$O(\frac{n}{\frac{\log n}{1 + \epsilon}} \log n) = O(\frac{n (1 + \epsilon)}{\log n} \log n) = O(\frac{n}{\log n} \log n) = O(n)$の時間・空間で計算できる。
</p><p>
問題はブロック中の"エッジ"ケースだが、これは以下のトリックによって解決できる。
</p><p>
$\frac{\log n}{1 + \epsilon}$サイズのブロックの中を「$\{+,-\}$の列」として考えたとき、相違なる個数は、$O(2^{\frac{\log n}{1 + \epsilon}}) = O(n^{\frac{1}{1 + \epsilon}})$個である。
それぞれに対して$O(\log^2 n)$のテーブルを事前計算しても、$O(n^{\frac{1}{1 + \epsilon}} \log^2 n) ⊆ O(n)$の時間・空間しかかからない。
さらにブロックごとに最初の値を記録しておけばブロック中の任意のRMQが求められる。
</p><p>
クエリではまずブロック中のエッジ部分をテーブルによって求め、さらに区間が覆うブロック列でsparse tableのクエリを使って求め、それらの最小値を取る。
</p><p>
クエリ問題版で前計算$O(n)$時間, $O(n)$空間, クエリ$Θ(1)$時間を達成する。
</p>