rmq(区间最值问题)

rmq

RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为 n n n的数列 A A A

A [ i ] A[i] A[i]是要求区间最值的数列, F [ i , j ] F[i, j] F[i,j]表示从第 i i i个数起连续 2 j 2^j 2j个数中的最大值。(DP的状态)

例如:

A数列为:3 2 4 5 6 8 1 2 9 7

F [ 1 , 0 ] F[1,0] F[10]表示第1个数起,长度为 2 0 = 1 2^0=1 20=1的最大值,其实就是 3 3 3这个数。同理

F [ 1 , 1 ] = m a x ( 3 , 2 ) = 3 F[1,1] = max(3,2) = 3 F[11]=max(3,2)=3

F [ 1 , 2 ] = m a x ( 3 , 2 , 4 , 5 ) = 5 F[1,2]=max(3,2,4,5) = 5 F[12]=max(3,2,4,5)=5

F [ 1 , 3 ] = m a x ( 3 , 2 , 4 , 5 , 6 , 8 , 1 , 2 ) = 8 ; F[1,3] = max(3,2,4,5,6,8,1,2) = 8; F[13]=max(3,2,4,5,6,8,1,2)=8;

并且我们可以容易的看出 F [ i , 0 ] F[i,0] F[i,0]就等于 A [ i ] A[i] A[i]。(DP的初始值)

这样,DP的状态、初值都已经有了,剩下的就是状态转移方程。

我们把 F [ i , j ] F[i,j] F[ij]平均分成两段(因为 f [ i , j ] f[i,j] f[ij]一定是偶数个数字),

i i i i + 2 ( j − 1 ) − 1 i + 2 ^ {(j - 1)} - 1 i+2(j1)1为一段, i + 2 ( j − 1 ) i + 2 ^ {(j - 1)} i+2(j1) i + 2 j − 1 i + 2 ^ j - 1 i+2j1为一段

(长度都为 2 ( j − 1 ) 2 ^ {(j - 1)} 2(j1))。用上例说明,当 i = 1 , j = 3 i=1,j=3 i=1j=3时就是 3 , 2 , 4 , 5 3,2,4,5 3,2,4,5 6 , 8 , 1 , 2 6,8,1,2 6,8,1,2这两段。 F [ i , j ] F[i,j] F[ij]就是这两段各自最大值中的最大值。

于是我们得到了状态转移方程:

F [ i , j ] = m a x ( F [ i , j − 1 ] , F [ i + 2 ( j − 1 ) , j − 1 ] ) F[i, j]=max(F[i,j-1], F[i + 2^{(j-1)},j-1]) F[i,j]=maxF[ij1],F[i+2(j1)j1]

在这里插入图片描述

void RMQ(int num)  //预处理
{
  for(int i = 1;i <= num; i++){
  	  int tmp; scanf("%d",&tmp);
  	  dp1[i][0] = dp[i][0] = tmp; // 注意理解dp的含义
  }
  for(int j = 1;1<<j) <= num; j++) 
   		for(int i = 1; i <= num; i++) 
   			 if(i + (1<<j) - 1 <= num)
   			 {
     			 dp1[i][j] = max(dp1[i][j-1], dp1[i+(1<<(j-1))][j-1]);
     			 dp2[i][j] = min(dp2[i][j-1], dp2[i+(1<<(j-1))][j-1]);
   			 }
   			 
}

i和j 的位置不能互相调换,先用两个 2 0 2^0 20的来更新一个 2 1 2^1 21 ,扫完一遍后,用两个 2 1 2^1 21 来更新一个 2 2 2^2 22,再扫一遍…

这样并不能直接求区间的最大最小值,查询区间的长度还是二的整数倍

不妨举个例子:

定义一个整数 z z z。查询 [ x , y ] [x,y] [x,y] 区间的最大和最小值,注意区间长度是 y − x + 1 y-x+1 yx+1

z z z 取到 2 z < = y − y + 1 2^z <= y-y+1 2z<=yy+1 并且 2 z + 1 > y − x + 1 2^{z+1} > y - x + 1 2z+1>yx+1

原因:最大值/最小值可以取操作 :

在这里插入图片描述

查询已经预处理好的区间

int z = 0;
while(1<<(z+1) <= (y-x+1)) z++;  // 区间取[x, y]
int Max = max(dp1[x][z], dp1[y-(1<<z)+1][z]);
int Min = min(dp2[x][z], dp2[y-(1<<z)+1][z]);

RMQ算法详解 - gaoyanliang - 博客园 (cnblogs.com)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值