RMQ

RMQ

解釋:

RMQ 問題是求給定區間中的最值問題,如下圖所示:
RMQ 問題(圖中記錄的是最小值的位置)
當然,最簡單的算法是 O(n)的,但是對於查詢次數很多 m(假設有 100 萬次),則這個算法的時
間複雜度爲 O(mn),顯然時間效率太低。可以用線段樹將查詢算法優化到 O(logn)(在線段樹中保
存線段的最值) ,而線段樹的預處理時間複雜度爲 O(n),線段樹整體複雜度爲

ST表:

解釋:

ST 算法,即 Sparse Table 算法。下面把 ST 算法分成預處理和查詢兩部分來說明(以求最小值
爲例),它的時間複雜度爲

1.1.1  預處理:lll
預處理使用 DP 的思想,f(i, j)表示[i, i+2^j ­ 1]區間中的最小值,即 f[i,j]表示從第 i 個數起連
RMQ 和 LCA 
­ 2 ­ 
續 2^j 個數中的最小值。我們可以開闢一個數組專門來保存 f(i, j)的值。
例如,f(1, 0)表示[1,1]之間的最小值,就是 num[1];f(1, 2)表示[1, 4]之間的最小值, f(2, 4) 
表示[2, 17]之間的最小值。
注意, 因爲 f(i, j)可以由 f(i, j  ­  1)和 f(i+2^(j­1), j­1)導出, 而遞推的初值(所有的 f(i, 0) 
=num[i])都是已知的。所以我們可以採用自底向上的算法遞推地給出所有符合條件的 f(i, j)的值。
ST 算法(圖中記錄的是最小值的位置) 
ST 算法的狀態轉移方程:
1 
[ ] , 0 
( , )
min ( ( , 1), ( 2 , 1), 0
j 
a i j  f i j  f i j f i j j -
Ï =
= Ì
Ó - + - >
例 如 : f(2,3) 保 存 的 是 a[2],a[3],a[4],……,a[9] 中 的 最 小 值 , 而
f(2,3)=min(f(2,2),f(6,2))=min((a[2],a[3],a[4],a[5]),(a[6],a[7],a[8],a[9]))
1.1.2  查詢:
假設要查詢從 m  到 n  這一段的最小值,  那麼我們先求出一個最大的 k,  使得 k  滿足
2 ( 1)
k £ n - m + ,於是我們就可以把[m,  n]分成兩個(部分重疊的)長度爲 2
k
的區間:
[ , 2 1]
k
m m + - , [ 2 1, ]
k
n - + n ; 
而 我 們 之 前 已 經 求 出 了 f (m, k ) 爲 [ , 2 1]
k  m m + - 的 最 小 值 , ( 2 1, )
k f n - + k 爲
[ 2 1, ]
k
n - + n 的最小值。
我們只要返回其中更小的那個, 就是我們想要的答案, 這個算法的時間複雜度是 O(1)的。
RMQ 和 LCA 
­ 3 ­ 
k= trunc(ln(r­l+1)/ln(2)); // 求[l,r]之間的最小值
ans:=max(F[l,k],F[r­2^k+1,k]);
例如, rmq(1,12) = min(f(1,3), f(5,3)) ( 2 k = log (12 -1+1) = 3 ) 
ST 算法的 O(1)查詢(有部分重疊)
function max(x,y: longint): longint;
begin
max:=x;
if y>x then max:=y;
end;
function query(s,t: longint): longint;  // 查詢[s,t]間的最大值
var
k: longint;
begin
k:=trunc(ln(t­s+1)/ln(2)); 
query:=max(a[s,k],a[t­(1<<k)+1,t]);  // 即max(a[s,k],a[t­2^k+1,t])
end;
procedure init;
var
i,j,p: longint;
begin
assign(input,'rmq­st.in');
reset(input);
readln(n);
for i:=1 to n do read(a[i,0]); 
p:= trunc(ln(n)/ln(2));
for j:=1 to p do // a[i,j]表示從i開始,2^j個元素的最大值
for i:=1 to (n­(1<<j)+1) do // n­(1<<j)+1 即 n­2^j+1 
a[i,j]:=max(a[i,j­1],a[i+1<<(j­1),j­1]);
close(input);
end;

1.2 巧妙易實現的分塊 ­­ sqrt(n)算法: (★★★)

把數組分割成 sqrt(n)大小的段。用一個數組 M[1..sqrt(n)]爲每一段保存最小值(或位置)。
M 可以很容易在 O(n)時間內完成預處理。
如在上例中,計算 RMQ(3,8)的值,我們應該比較 A[3]、M[2]、A[7]、A[8]值即可。可以很容
易看出這個算法每一次查詢不會超過 3*sqrt(n)次操作。
這個方法非常容易實現,並且還可以將它改成問題的動態版本 .... (邊查詢、邊改元素)。

發佈了57 篇原創文章 · 獲贊 76 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章