范围最小值(RMQ)问题

问题:

  给出一个n个元素的数组,a[1], a[2], …… , a[n],设计一个数据结构,支持查询操作RMQ(L, R),计算min{a[L], a[L+1], …… , a[R]}。

分析:

  循环计算会超时,用Tarjan的Sparse-Table算法,预处理时间是O(nlogn),查询只需要O(1)。

  令d[i][j]表示从i开始,长度为2的j次方的一段元素的最小值。

  则d[i][j] = min(d[i][j-1], d[i+(1<<(j-1)][j-1])。

代码:

  

#include <cstdio>
#include <algorithm>
//#include <cmath>
using namespace std;
const int MAX = 100;
int n, a[MAX+10];
int d[MAX+10][MAX+10];//二维应该是floor(log(1.0*MAX)/log(2.0)),但是不知为什么编译有问题。。
int RMQ(int l, int r)
{
    int k = 0;
    while((1<<(k+1)) <= r-l+1)k++;
    //也可以k = log(1.0 * r-l+1)/log(2.0);
    return min(d[l][k], d[r-(1<<k)+1][k]);
}
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    for(int i = 1; i <= n; i++)
        d[i][0] = a[i];
    for(int j = 1; (1<<j) <= n; j++)
        for(int i = 1; i+(1<<j)-1 <= n; i++)
            d[i][j] = min(d[i][j-1], d[i+(1<<(j-1))][j-1]);
    int l, r;
    while(scanf("%d %d", &l, &r) != EOF)
        printf("%d\n", RMQ(l, r));
    return 0;
}

 

posted @ 2013-05-29 21:21  Anti-Magic  阅读(165)  评论(0编辑  收藏  举报