RMQ 区间最值查询 入门

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;
}

原文地址:https://www.cnblogs.com/alking1001/p/12309982.html