C++ RMQ问题

RMQ问题是区间求最值问题,就是求一个数组第i个到第j个中最大数或最小数的算法。

这个算法有一些倍增思想,也有一些二分思想。具体是一个数组,m[i][j]表示从i开始往后数2的j次方个数的最大值或最小值是几。

我们可以很明显的看出,m[i][j]=max(m[i][j-1],m[i+pow(2,j-1)][j-1]);这样就能求出所有i后2的j次方里最大的数了。

但是有一个问题,(可能只有我不会。)如果让查找的区间长度不是2的次方怎么办?我也是想了30分钟。得到了结果,让中间重合一部分,凑成2的log(r-l+1)+1次方。就可以了。

具体操作是max(l开始向后查看2的log(r-l+1)次方,r向前查看2的log(r-l+1)次方),或者min。这样每次运行都是2的次方,也没有多查找。

正经代码来了:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
long long m[20][20],mx[20][20],md[20][20],l,r,n,mid,d,x;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>m[i][0];
		mx[i][0]=m[i][0];
		md[i][0]=m[i][0];
	}
	for(int j=1;j<=20;j++)
	{
		for(int i=1;i+pow(2,j)<=n;i++)
		{
			mx[i][j]=min(mx[i][j-1],mx[i+(int)pow(2,(double)j-1)+1][j-1]);
			md[i][j]=max(md[i][j-1],md[i+(int)pow(2,(double)j-1)+1][j-1]);
		}
	}
	cin>>l>>r;
	mid=log(r-l+1);
	d=max(md[l][mid],md[r-(int)pow(2,(double)mid)][mid]);
	x=max(mx[l][mid],mx[r-(int)pow(2,(double)mid)][mid]);
	cout<<d<<endl;
	return 0;
}

 应该是对的,大家懂了吗,自己试试吧。

猜你喜欢

转载自www.cnblogs.com/lichangjian/p/12418914.html