码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-05-19 14:47:16      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:rmq   hiho   

问题描述

给定一个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;
}

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

标签:rmq   hiho   

原文地址:http://blog.csdn.net/barry283049/article/details/45843735

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!