范围最小值问题(Range Minimum Query,RMQ)

问题描述

给定一个n个元素的序列{A1,A2,……,An},在要求的区间Query(L,R)内找到最小值:min{AL,AL+1,……,AR}。hiho16

算法描述

在这里介绍最常用的Tarjan的Sparse-Table算法,它的预处理时间复杂度为O(nlogn),而查询时间只需要O(1)。令calc(i,j)表示从i开始的,长度为2j 的一段子序列的最小值,则使用循环的方式计算:calc[i][j] = min(calc[i][j-1],calc[i+2j-1)][j-1]),代码如下:

void RMQ_init(void){
    int index = floor(log(n) / log(2));
    for (int j = 1; j <= index; j++) {
        for (int i = 1; i+(1<<j)-1<=n; i++){
            calc[i][j] = min(calc[i][j-1],calc[i+(1<<(j-1))][j-1]);
        }
    }
}

注:这里序列从索引1开始。
预处理完成后,如何使用该信息呢,对于一个查询[L,R],只要找到小于这个区间长度的最大的2的非负整数次幂的指数——j,那么这个区间中的最小值就是min{calc[L][j], calc[R-2j+1][j]},通过这两段区间可以覆盖整个[L,R]区间,同时即使两端区间有交集也不影响最小值的确定。

代码

#include<cstdio>
#include<algorithm>
#include<math.h>
#define SIZE 1000005
using namespace std;
int arr[SIZE];
int calc[SIZE][20];
int n, q;
void RMQ_init(void){
    int index = floor(log(n) / log(2));
    for (int j = 1; j <= index; j++) {
        for (int i = 1; i+(1<<j)-1<=n; i++){
            calc[i][j] = min(calc[i][j-1],calc[i+(1<<(j-1))][j-1]);
        }
    }
}
int main(void) {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++){
        scanf("%d", arr + i);
        calc[i][0] = arr[i];
    }
    RMQ_init();
    scanf("%d", &q);
    int l, r;
    for (int i = 0; i < q; i++){
        scanf("%d%d", &l, &r);
        int j = floor(log(r - l + 1) / log(2));
        int rr = r - (1<<j) + 1;
        printf("%d\n", min(calc[l][j], calc[rr][j]));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值