RMQ--ST算法

RMQ又是区间查询问题:例如,给定一个数组A[i],给你任意段区间,[L_{_{}1},R_{1}],[L_{_{}2},R_{2}],\cdots ,[L_{_{}n},R_{n}],求这些区间的最值(可以最大值,也可以最小值)。

解决算法:ST (Sparse - Table算法,基于动态规划求区间最值的算法) 

这个算法的核心在于二维数组f[i][j]的预处理作用,由它来表示出状态转移方程。f[i][j]表示从第i个数开始的2^{j}个数(这个区间)的最值。状态转移方程可有长度递增推出来,是下列的形式:

                                                                        f[i][j]=max(f[i][j-1],f[i+2^{j-1}][j-1])

大白话翻译就是从第i个数开始的2^{j}个数的最大值=max(从第i个数开始的2^{j-1}个数的最大值,从第i+2^{j-1}位置开始的2^{j-1}个数的最大值),最小值同理。左右两个区间的数的个数合起来正好是2^{j}个。

对边界的处理:边界条件为F[i][0]=A[i]。

接下来就是查询,这里k=log(R-L+1)/log(2),首先这是一个换底公式,所以其实是k=log_{2}(R-L+1),k表示这个区间长度。

还有一点就是为什么RMQ循环里面的外层循环是j,而内循环是i。可以这样想,我们每次求f[i][j]的时候都要保证f[i][j-1]已经求过,但是f[i+2^{j-1}][j-1]没有保证j-1i+2^{j-1}是求过的,把i循环放里面,你只有当把这一层所有的i循环都求过了,才可以保证这一点。

代码算是一个模板,我根据https://blog.csdn.net/chenzhenyu123456/article/details/47298867这个博客来的,加上了自己的思考,博文还有降维,即一维数组就搞定了,确实很强,这里我先给出二维的,一维的等我理解到一定程度了再补上!

代码如下:

#include<iostream>
#include<math.h>
#include<algorithm>
#include<string.h>
#define MAXN 10020
#define INF 0x3f3f3f3f
using namespace std;
int A[MAXN];
int N,M;
int Amax[MAXN][50]; //Amax[i][j]表示从i开始的,长度为2的j次方的区间里面的最大值
int Amin[MAXN][50];//Amin[i][j]表示从i开始的,长度为2的j次方的区间里面的最小值
void RMQ()
{
	for(int i=1;i<=N;i++)
	    Amax[i][0] = Amin[i][0] = A[i];
	for(int j=1;(1<<j) <= N;j++)
	{
		for(int i=1;i+(1<<j)-1 <= N;i++)
		{
			Amax[i][j] = max(Amax[i][j-1],Amax[i+(1<<(j-1))][j-1]);
			Amin[i][j] = min(Amin[i][j-1],Amin[i+(1<<(j-1))][j-1]);
		}
	}
 } 
 int query(char *op,int L,int R)
 {
 	//两种求k的方法 
 	/*int k=0;
 	while((1<<(k+1)) <= R-L+1) 
 	    k++;*/ 
 	int k = (int)(log(double(R-L+1))/log((double)2));
 	if(strcmp(op,"MAX") == 0)
 	    return max(Amax[L][k],Amax[R-(1<<k)+1][k]);
 	else
 	    return min(Amin[L][k],Amin[R-(1<<k)+1][k]);
 }
 int main()
 {
 	while(cin>>N>>M&&N&&M)
 	{
 		for(int i=1;i<=N;i++)
 		    cin>>A[i];
 		RMQ();
 		char s[10];
 		int x,y;
 		while(M--)
 		{
 			cin>>s>>x>>y;
 			cout<<query(s,x,y)<<endl;
		 }
	 }
	 return 0;
	 
 }
 

运行结果如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值