RMQ nyoj119

题目链接http://acm.nyist.net/JudgeOnline/problem.php?pid=119

大致题意是求区间最值问题,若采取常规方法,当数据数量大时,时间复杂度为O(n^2),不是一个好的方法。

下面介绍一种RMQ算法,RMQ故名思意 Range Minsum/Maxsum Query,求区间的最大与最小值

RMQ是一种DP的思想。

Step 1.预处理,过程耗时O(nlogn)

设A[i]是要求区间最值的数列,不妨设maxsum[i][j],表示从A[i]起的连续2^j个数的最大值,同理minsum。

如maxsum[1][0],2^0=1,即maxsum[i][0]=A[i];

  maxsum[1][3]即为区间 A[1]....A[8]的最大值

DP就得有状态转移方程

 这里运用了二分的思想

 有状态方程

  maxsum[i][j]=max(maxsum[i][j-1],maxsum[i+2^j-1][j-1]);

同理 minsum[i][j]=min(minsum[i][j-1],minsum[i+2^j-1][j-1]);

Step 2

查询区间最值

同样有个方程

maxsum[x][y]=max(maxsum[x][k],maxsum[y-(1<<k)+1][k]; 其中k为log(y-x+1.0)/log(2.0)

举例maxsum[2][8]=max(max[2][2],maxsum[5][2]) maxsum[2][2]=max(A[2],A[3],A[4],A[5]);

 maxsum[5][2]=max(A[5],A[6],A[7],A[8]);

下面来看这道题,注意+的运算优先级大于<<。

AC代码:

#include<stdio.h>
#include<iostream>
#include<cmath>
using namespace std;
#define N 1000010
int maxsum[N][20],minsum[N][20];
void RMQ(int num)
{
 int i,j;
 for(j=1;j<20;j++)
 for(i=1;i<=num;i++)
 {
  if(i+(1<<j)-1<=num)
  {
   maxsum[i][j]=max(maxsum[i][j-1],maxsum[i+(1<<j-1)][j-1]);
   minsum[i][j]=min(minsum[i][j-1],minsum[i+(1<<j-1)][j-1]);
  }
 }
}
int main()
{
 int num,q;
 scanf("%d%d",&num,&q);
 for(int i=1;i<=num;++i)
 {
  scanf("%d",&maxsum[i][0]);
  minsum[i][0]=maxsum[i][0];
 }
 RMQ(num);
 while(q--)
 {
  int x,y,k;
  scanf("%d%d",&x,&y);
  k=int(log(y-x+1.0)/log(2.0));
  maxsum[x][y]=max(maxsum[x][k],maxsum[y-(1<<k)+1][k]);
  minsum[x][y]=min(minsum[x][k],minsum[y-(1<<k)+1][k]);
  printf("%d\n",maxsum[x][y]-minsum[x][y]);
 }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值