1. 程式人生 > >區間最值查詢(RMQ)

區間最值查詢(RMQ)

ST演算法

預處理第i位起連續2^k個數的最大值,快速查詢。
說明:定義陣列dp[i][j]表示 從第i位起連續2^j個數 的最大值。
(區間內有2^j個數)
例子: 2 5 9 6 3 1
dp[1][2] 第1位起連續2^2(4)個: {2,3,9,6}

預處理:

  1. dp[i][0]有一個,等於它本身。
    從給定的排列我們可知全部的dp[i][0];
    從全部的dp[i][0] (長度=1),兩兩求max,我們可以得到全部的dp[i][1](長度=2);
    再從全部的dp[i][1](長度=2),兩兩求manx,我們可以得到全部的dp[i][2](長度=4);
    ……
    好的,我們發現這就是動態規劃。

  2. 兩兩求max,我們把2^j(長度)一切二: 2^(j-1) + 2^(j-1)
    i起2^(j-1)個 與 (i+2^(j-1))起2^(j-1)個
    狀態轉移方程我們也可以求得:

dp[i][j]=max(dp[i][j-1],dp[i+2^(j-1)][j-1]);

void RMQ(int num){  
    for(int j = 1; j < maxn; ++j)  
        for(int i = 1; i <= num; ++i)  
            if(i + (1 << j) - 1 <= num)  
            {  
                maxsum[i][j] = max
(maxsum[i][j - 1], maxsum[i + (1 << (j - 1))][j - 1]); minsum[i][j] = min(minsum[i][j - 1], minsum[i + (1 << (j - 1))][j - 1]); } }

說明:根據步驟1 我們可以知道 當我們有dp[i][0]後再求 所有的dp[i][1];所以我們先遍歷完所有i後再求j ,即j巢狀在i上面。

查詢

設範圍left ,right ;
查詢長度len = right-left +1;
對dp[][]陣列中預處理 2^k 長度來說,我們需要把查詢長度 len也變為 2^k的形式:
但查詢長度不可能正好 2^k長,那就分為兩段,進行覆蓋查詢:
一段從頭開始覆蓋,一段從尾開始覆蓋
分成的兩段,每段長 2 的 log2(len)次方 (取整)


比如 :
查詢 {3,4,1,6,7,2} 長度為6;
我們預處理查詢長度為 2^2(4 <6(取整))
即查詢 {3,4,1,6} 和{1,6,7,2}

如果設預處理查詢長度為 2^k的話,那麼我們的查詢表示式為:
res=max(dp[left][k],dp[right-2^k+1][k]) ;