RMQ 总结

RMQ是 range maxm\imum(minimum) query 的缩写,是用来求某个区间内的最大值或者最小值,通常用在需要多次询问一些区间的最值问题中。


RMQ的原理是动态规划:

用A[1……N]表示一组数, F[I,J]表示从A[I]到A[I+2^j - 1]这个范围内的最大值,由于元素个数为2^J个,所以从中间平均分成两部分,每一部分的元素个数刚好为 2^(j-1)个。

整个区间的最大值一定是左右两部分最大值的较大值,满足动态规划的最优化原理

状态转移方程:

F[I,J] = max(F[I, J-1], F[I + 2^(J-1), J-1])

边界条件为F[I,0]= A[I];

这样就可以在O(NlgN)的时间复杂度内预处理F数组。

预处理代码:

for(int i = 1 ; i <= mn; i++)
    f[i][0] = a[i];
for(int j = 1; 1 << j <= n; j++)
   for(int i = 1; i+(1<<j)-1 <= n; i++)
      f[i][j] = max( f[i][j-1], f[i+(1<<j-1)][j-1]);


对于询问区间[L,R],求出最大的x,满足2^x<= R-L+1,即 x = trunc(ln(R-L+1) / ln(2)),两个子区间元素个数都是2^x个,

ans= max(F[L,x],F[R+1-2^x,x]);

询问操作代码:

long query(int L, int R)
{
      	int x = int(ln(R-L+1) / ln(2));
      	return max( f[L][x], f[R-(1<<x)+1][x]);
}


#include <iostream> //区间问题 
#include <cmath>
#include <cstdio>
using namespace std;
int RMQ[100000][23], n, m;
int ASK(int L, int R)
{
	int x = (int)(log(R-L+1) / log(2));
	return max(RMQ[L][x], RMQ[R-(1<<x)+1][x]);
}
void ST()
{
	int i , j;
	for(i = 1; i <= n; i++)
	   cin>> RMQ[i][0];
	for(j = 1; j <= (int)(log(n)/log(2)); j++)
	  for( i = 1; i+(1<<j)-1 <= n; i++)
	     RMQ[i][j] = max(RMQ[i][j-1], RMQ[i+(1<<j-1)][j-1]);
}
int main()
{
	int i, x, y;
	cin >> n >> m;
	ST();
	for( i = 1; i <= m; i++)
	{
		scanf("%d%d", &x,&y);
		printf("%d\n", ASK(x,y));
	}
	return 0;
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值