区间最值查询(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,5,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);
    ……
    好的,我们发现这就是动态规划。

两两求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( 2 = log2(6)(向下取整))
即查询 {3,4,1,6} 和{1,6,7,2}

获得了预处理查询长度2^k后,那么我们的查询表达式为:
res=max(dp[left][k],dp[right-2^k+1][k]) ;

你可能感兴趣的:(区间最值查询(RMQ))