區間最值查詢(RMQ)
阿新 • • 發佈:2019-02-02
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}
預處理:
dp[i][0]有一個,等於它本身。
從給定的排列我們可知全部的dp[i][0];
從全部的dp[i][0] (長度=1),兩兩求max,我們可以得到全部的dp[i][1](長度=2);
再從全部的dp[i][1](長度=2),兩兩求manx,我們可以得到全部的dp[i][2](長度=4);
……
好的,我們發現這就是動態規劃。兩兩求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]) ;