RMQ入门

一:简介

OI Wiki上是这么说的

RMQ 是英文 Range Maximum/Minimum Query 的缩写,表示区间最大(最小)值。

二:作用

用来求区间内的最大(最小)值

三:实现

RMQ的实现有很多种算法,不过作者这里选择用ST表来解决

1.理论

我们发现max(x,x) = x 

也就是说,区间最大值是一个具有「可重复贡献」性质的问题。

即使用来求解的预处理区间有重叠部分,只要这些区间的并是所求的区间,最终计算出的答案就是正确的。

如果手动模拟一下,可以发现我们能使用至多两个预处理过的区间来覆盖询问区间,也就是说询问时的时间复杂度可以被降至O(1) ,在处理有大量询问的题目时十分有效。

2.实践

我们设置maxn[i][j] 表示区间[i,i+2^{j}-1]的最大值(最小值同理)

那么当j!=0时,maxn[i][j]就可以简化成max(maxn[i][j-1],maxn[i+2^{j}][j-1])

那现在我们就预处理完了,那我们怎么求呢?

我们可以把它分为两个区间

设l为左端点,r为右端点,x为r到l的个数为2的几次方

所以[l,r]的最大值为max(maxn[l][x],maxn[r-s[x]+1][x])

最后,我们可以求出2^{i}分别是多少,用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";
    }
}

四:结语

如果本文对您有帮助的话,不要忘记点赞收藏加关注支持一下吖~

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值