概念:
RMQ指的是Range Minimum/Maximum Query 即为区间最值问题。
优点:
此问题放眼看去似乎是一个比较简单的问题,我们可以直接朴素算法走一遍区间,找到最值即可,但是这样的话时间复杂度为O(n2)
如果题目中所给的有多个询问,这时候我们如果还坚持朴素算法的话,必然会超时。这时候RMQ算法的优势就体现出来了
初始化需要的时间复杂度接近O(nlogn),但是查询的时间复杂度为O(1)
递推:
(1)思想:
要从小区间递推到大区间,我们这里采用了分割的方式,也就是先找 [a,a+2^0 -1] 的最值,然后再找 [a + 2^0 ,a + 2^0 + 2 ^0 - 1],这里我们列举的是初始区间,然后这两个区间合并成大区间[a,a + 2^0 + 2 ^0 - 1]。
(2)关系:
dp[i][j] = max(dp[i][j-1],dp[i + (1 << (j -1))][j - 1])
dp[i][j]:以i为起点,区间长度为2^j时的区间最值
例题:Balanced Lineup
FJ 的 NN 头牛总是按同一序列排队。有一天,FJ 决定让一些牛玩一场飞盘比赛。他准备找一群在对列中为置连续的牛来进行比赛,但是为了避免水平悬殊,牛的身高不应该相差太大。FJ 准备了 QQ
个可能的牛的选择和所有牛的身高。他想知道每一组里面最高和最低的牛的身高差别。输入格式
第一行:N 和 Q; 第二至第 N+1行,第 i+1 行是第 i 头牛的身高 h_ih i ;
第 N+2N+2 至第 N+Q+1 行,每行两个整数 A 和 B,表示从 A 到 B 的所有牛。输出格式
第一至第 Q 行,每行一个整数,表示对于询问的回答(即最高和最低的牛的身高差)。
RMQ 模板,同时拥有最大值和最小值的求解
#include<iostream>
using namespace std;
const int N=5e4+10,logN=20;
int mi[N][logN+5],mx[N][logN+5],log[N];
int n,m;
int main()
{
ios::sync_with_stdio(0);
cin>>n>>m;log[0]=-1;
for(int i=1;i<=n;i++)
{
int a;
cin>>a;
mi[i][0]=mx[i][0]=a;
log[i]=log[i>>1]+1;//最大<=长度i的2的次方数
}
for(int j=1;j<logN;j++)//枚举区间长度
for(int i=1;i+(1<<j)-1<=n;i++)//枚举区间左端点
mi[i][j]=min(mi[i][j-1],mi[i+(1<<j-1)][j-1]),
mx[i][j]=max(mx[i][j-1],mx[i+(1<<j-1)][j-1]);
while(m--)
{
int l,r;
cin>>l>>r;
int s=log[r-l+1];
cout<<max(mx[l][s],mx[r-(1<<s)+1][s])-min(mi[l][s],mi[r-(1<<s)+1][s])<<endl;
//把当前区间分为【l,l+2^k】和【r-2^k+1,r】两区间
}
return 0;
}