RMQ学习ing

做后缀数组卡了一天,发现要学RMQ。。。

如此一环套一环地学下去,什么时候才能学到后缀自动机QAQ

求区间最值:给出一组数据,给出m组查询,每组查询求一个区间的最值。

线段树查询的复杂度是O(mlogn),RMQ的查询复杂度是O(n)。在RMQ中,只要预处理(复杂度为O(nlogn))后,每个区间都可以O(1)求出最值,这就是在时间上优于线段树的地方。不过相对应地空间付出了代价,线段树只需开4倍空间即可,RMQ每次要开logn倍的空间,空间消耗是线段树的很多倍。


#include <stdio.h>
#include <math.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <iostream>
#include <assert.h>
#define INF 0x3f3f3f3f
using namespace std;


//区间最小值查询(最大值改改就OK)
//预处理O(nlogn),查询O(n)
const int M = 1e5 + 10;
int Log[M]; //Log[i]表示i这个数在第几层
int rmq[M][20]; //rmq[i][j]表示,从第i位到第i+2^j-1位的最小值(两边都是闭区间),区间长度为2^j
int a[M]; //输入的数组

void rmqinit(int n) //预处理
{
  Log[0] = Log[1]= 0;
  for (int i = 2; i <= M; i++) 
    Log[i] = Log[i >> 1] + 1; //i在第几层

  for (int i = 1; i <= n; i++)
    rmq[i][0] = a[i]; //初始化,每个第i位的最值就是它本身
  for (int j = 1; j <= Log[n]; j++) {
    int k = 1 << (j - 1);
    //i+(1<<j)-1<=n  防止爆空间。卿爷说一般开两倍空间,就可以不写这句话,但这样写节约空间
    for (int i = 1; i + (1 << j) - 1 <= n; i++) { 
      rmq[i][j] = min(rmq[i][j - 1], rmq[i + k][j - 1]);
    }
  }
}

int rmquery(int a, int b) //查询
{
  //查询x-y的最值,找到中间的两个数xx,yy,取x-xx,yy-y两段的最值就OK
  //懂原理的话这里就好懂很多
  int t = Log[b - a + 1]; //查询的这段的长度在第几层
  return min(rmq[a][t], rmq[b - (1 << t) + 1][t]);
}

int main()
{
  int n;
  while (cin >> n) {
    for (int i = 1; i <= n; i++)
      scanf("%d", &a[i]);
    rmqinit(n);
    for (int i = 1; i <= n; i++) {
      for (int j = i; j <= n; j++) {
        cout << i << "~" << j << "~" << rmquery(i, j) << endl;
      }
    }
  }
  return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值