范围最小值(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;

}

 

你可能感兴趣的:(MQ)