RMQ问题

匿名 (未验证) 提交于 2019-12-03 00:43:02

一:引入

RMQ是求某个区间内的最大值或最小值。

RMQ的求解方法-----ST算法

二:ST算法

ST算法利用了动态规划。这里假设有arr[1..n]一组数,设f[i][j]表示从 a[i]a[i+(2^j)-1] 的最大值,也就是以a[i]为起点的连续2^j个数的最大值。由于数个数有2^j个,所以从中间平均分为两部分,每一部分的数的个数为2^(j-1)个。

动态规划最优化原理。所以,我们可以得到这样的一个状态转移方程:f[i][j]=max(f[i][j-1] , f[i+2^(j-1)][j-1],边界为

.。我们可以用

(n*log(n))的时间复杂度预处理f数组;

2.询问:

若我们要询问区间[L,R]的最大值,那么,我们需要先求出最大的x满足2^x <=R-L+1,那么区间[L,R]的最大值便是

;其中:第一个区间表示 L 到 L+2^x-1 的最大值,第二个区间表示R-2^x+1 到 R的最大值。现在看一下,是不是成功的求出了最大值?(因为2^x <=R-L+1 就说明 第二区间的左端点在L的右边,两者去掉重复的线段正好是L到R(有重复没关系,因为max这个函数是不管这些的))

三:一点小技巧

因为cmath中的log2的函数效率不高,所以,还是自己写吧。

四:代码

ST算法模板题面――点击转入luogu

 #include<bits/stdc++.h> using namespace std; const int maxn=1e5+10; int f[maxn][25],a[maxn],n,m,x,Log[maxn],y; int main() {     scanf("%d%d",&n,&m);//n代表序列长度,m代表询问次数;     for(int i=1;i<=n;++i){scanf("%d",&a[i]);f[i][0]=a[i];}//预处理;     Log[0]=-1;//初始化一下;     for(int i=1;i<=n;++i)     {         Log[i]=Log[i/2]+1;//用一下小技巧;     }      for(int j=1;j<=22;++j)            for(int i=1;i+(1<<j)-1<=n;++i)                  f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);//动态规划公式运用;         for(int i=1;i<=m;++i)     {         scanf("%d%d",&x,&y);         int s=Log[y-x+1];//算出上文所说的x的值         printf("%d\n",max(f[x][s],f[y-(1<<s)+1][s]));//比较大小,输出;     } }

五:总结

ST是一个很好理解的算法。。。如果不懂,多看几遍其实就会了大半了。。。

文章来源: RMQ问题
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!