RMQ 区间最值查询 入门
博客推荐
讲解不错:https://blog.csdn.net/qq_41311604/article/details/79900893
一些细节讲解:https://blog.csdn.net/xi__long/article/details/36933515
总结
RMQ
(Range Minimum/Maximum Query)
,即区间最值查询。RMQ算法一般用较长时间做预处理,时间复杂度为O(nlogn)
,然后可以在O(1)
的时间内处理每次查询。
主要是来解决:给你一个数组 ,其中有N
个数字,现在给你多次询问,给你区间[l,r]
,问你在这个区间内的最值为多少?
我们设二维数组dp[i][j]
表示从第i位开始连续 $$2^j$$个数中的最小值。例如dp[2][1]
就表示从第二位数开始连续两个数的最小值(也就是从第二位数到第三位数的最小值),dp[i][0]
就表示第i
个数字本身。
模板代码
void rmq_init() //RMQ初始化
{
for(int i=1; i<=n; i++)
dp[i][0]=arr[i];
for(int j=1; (1<<j)<=n; j++)
for(int i=1; i+(1<<j)-1<=n; i++)
dp[i][j]=min(dp[i][j-1], dp[i+(1<<j-1)][j-1]); //i + (1 << (j - 1))
//左移操作符的优先级小于加号的优先级
}
//查询部分代码
int rmq(int l, int r)
{
int k=log2(r-l+1);
return min(dp[l][k], dp[r-(1<<k)+1][k]);
}
入门题目
POJ 3264
题意是说给你一系列的数,然后求给定区间上的最大值和最小值。
就是个模板题了,线段树也可以,但是RMQ
代码量更少。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<stack>
#include<queue>
#include<map>
typedef long long ll;
using namespace std;
const double esp=1e-6;
const int inf=0x3f3f3f3f;
const int MAXN=5e4+7;
int num[MAXN], madp[MAXN][20], midp[MAXN][20];
int n, q;
void init()
{
for(int i=1; i<=n; i++)
{
madp[i][0]=num[i];
midp[i][0]=num[i];
}
for(int j=1; (1<<j) <=n; j++)
for(int i=1; i+(1<<j)-1<=n; i++)
{
madp[i][j]=max(madp[i][j-1], madp[i+(1<<j-1)][j-1]);
midp[i][j]=min(midp[i][j-1], midp[i+(1<<j-1)][j-1]);
}
}
int rmq_max(int l, int r)
{
int k=log2(r-l+1);
return max(madp[l][k], madp[r-(1<<k)+1][k]);
}
int rmq_min(int l, int r)
{
int k=log2(r-l+1);
return min(midp[l][k], midp[r-(1<<k)+1][k]);
}
int main()
{
while(scanf("%d%d", &n, &q)!=EOF)
{
for(int i=1; i<=n; i++)
{
scanf("%d",&num[i]);
}
init();
int l, r;
for(int i=1; i<=q; i++)
{
scanf("%d%d",&l, &r);
printf("%d
", rmq_max(l, r)-rmq_min(l, r));
}
}
return 0;
}