RMQ区间最值

前言

区间最值问题就是一类求一段区间的最大值或者最小值的问题(好像是废话。。。),有时候区间很大,

比如[1~100000000],这样的长度,暴力是肯定不行的,所以这个时候就必须用更高效的算法来解决问题。

高级写法有两种解决方法:

一种是ST表,另一种是线段树。

这里只给出ST算法的形式,适合于静态区间,如果要求动态区间,那就老老实实线段树。

ST表

此算法是基于dp思想的一种解法

定义

dp( i,j )表示从第i位到第i+2j-1位这个2j长度的区间的最大值

预处理

dp( i, 0 )表示区间[ i, i ],所以初始化为a[i],表示区间[ i, j ]的最大值为a[ i ]

递推式

将长度为2j的区间分为两段长度为2j-1的区间,也就是[i,i+2j-1-1]和[i+2j-1,i+2j-1]两个区间,然后选取两个区间的最值。

dp( i,j )=max(dp( i, j-1 ),dp( i+2j-1, j-1 )

注意:上式圆括号后面都是 j-1,是因为i+2j-1+2j-1-1 = i+2j-1    ! ! !

建立代码

 1 //创建RMQ 
 2 void RMQ(int n){
 3     init(n);//初始化dp[i,0]
 4     //使用了左移符号 
 5     for(int j=1;(1<<j)<=n;j++){
 6         for(int i=1;i+(1<<j)-1<=n;i++){
 7             dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
 8         }
 9     }
10 }

注意外部循环从j开始, 因为初始状态为dp[i][0], 以 i 为外层会有一些状态遍历不到。

查询过程

 

如上图,一个区间为[ l, r ],长度为 r-l+1,将其转化为2k这种形式

也就是k=log2(r-l+1),那么就可以把原区间分成两个部分[l,l+2k-1-1][l+2k-1,r]

dp( l, r )=dp(l,k-1),dp(l+2k-1,k-1)

然而,由于log是向下取整,所以2k可能小于r-l-1,所以要用"两边夹"的方法来实现区间分离,如上图

则分开的区间为[l,i+2k-1][r-2k+1,r],并不需要担心重复,毕竟是求最值

也就是:

dp( l, r )=max(dp( l, k ),dp(r-2k+1,k))

最终代码

 1 #include<iostream>
 2 #include<cmath>
 3 using namespace std;
 4 const int maxn=200;
 5 int dp[maxn][maxn];
 6 //快速写入 
 7 inline int read(){
 8     int w=0,f=1;
 9     char ch=getchar();
10     while(ch<'0'||ch>'9'){
11         if(ch=='-') f=-1;
12         ch=getchar();
13     }
14     while(ch>='0'&&ch<='9'){
15         w=(w<<3)+(w<<1)+ch-48;
16         ch=getchar();
17     }
18     return w*f;
19 }  
20 //初始化 
21 inline void init(int n){
22     for(int i=1;i<=n;i++){
23         dp[i][0]=read();
24     }
25 }
26 //创建RMQ 
27 void RMQ(int n){
28     init(n);
29     //使用了左移符号 
30     for(int j=1;(1<<j)<=n;j++){
31         for(int i=1;i+(1<<j)-1<=n;i++){
32             dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
33         }
34     }
35 }
36 int main(){
37     int n=read();
38     RMQ(n);
39     int l=read();
40     int r=read();
41     //查询 
42     int k=log2(r-l+1);
43     printf("%d",max(dp[l][k],dp[r-(1<<k)+1][k]));
44     return 0;
45 } 

 

posted @ 2019-06-12 20:20  过眼灬云烟  阅读(255)  评论(2编辑  收藏  举报