一:简介
在OI Wiki上是这么说的
RMQ 是英文 Range Maximum/Minimum Query 的缩写,表示区间最大(最小)值。
二:作用
用来求区间内的最大(最小)值
三:实现
RMQ的实现有很多种算法,不过作者这里选择用ST表来解决
1.理论
我们发现max(x,x) = x
也就是说,区间最大值是一个具有「可重复贡献」性质的问题。
即使用来求解的预处理区间有重叠部分,只要这些区间的并是所求的区间,最终计算出的答案就是正确的。
如果手动模拟一下,可以发现我们能使用至多两个预处理过的区间来覆盖询问区间,也就是说询问时的时间复杂度可以被降至O(1) ,在处理有大量询问的题目时十分有效。
2.实践
我们设置maxn[i][j] 表示区间[i,i+-1]的最大值(最小值同理)
那么当j!=0时,maxn[i][j]就可以简化成max(maxn[i][j-1],maxn[i+][j-1])
那现在我们就预处理完了,那我们怎么求呢?
我们可以把它分为两个区间
设l为左端点,r为右端点,x为r到l的个数为2的几次方
所以[l,r]的最大值为max(maxn[l][x],maxn[r-s[x]+1][x])
最后,我们可以求出分别是多少,用s[i]表示
那么代码如下
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x*f;}//快读
int n,q;
int maxn[500000][22];
int s[22];//表示2的i次方是多少
signed main(){
n = read();
q = read();
s[0] = 1;
for(int i=1;i<=20;i++)s[i] = s[i-1]*2;
for(int i=1;i<=n;i++) maxn[i][0] = read();
int x = log2(n);
for(int i=1;i<=x;i++)
for(int j=1;j+s[i]-1<=n;j++)
maxn[j][i] = max(maxn[j][i-1],maxn[j+s[i-1]][i-1]);//预处理
for(int i=1;i<=q;i++){
int l,r;
l = read();
r = read();
x = log2(r-l+1);
int t1 = max(maxn[l][x],maxn[r-s[x]+1][x]);
cout<<t1<<"\n";
}
}
四:结语
如果本文对您有帮助的话,不要忘记点赞收藏加关注支持一下吖~