POJ3264 Balanced Lineup

http://poj.org/problem?id=3264

经典的RMQ题目。RMQ问题是求给定区间中的最值问题。朴素算法是O(n)的,用线段树可以将算法优化到O(logn)(在线段树中保存线段的最值)。

不过,只查询的话RMQ算法最合适:它可以在O(nlogn)的预处理以后实现O(1)的查询效率。线段树主要的区别是可以修改区间,RMQ不行。
下面把Sparse Table算法分成预处理和查询两部分来说明。 使用了倍增思想。
预处理:
以求最大值为例,设d[i,j]表示[i,i+2^j-1]这个区间内的最大值,那么在询问到[a,b]区间的最大值时答案就是max(d[a,k], d[b-2^k+1,k]),其中k是满足2^k<=b-a+1(即长度)的最大的k,即k=[ln(b-a+1)/ln(2)]。
d的求法可以用动态规划,d[i, j]=max(d[i, j-1],d[i+2^(j-1), j-1])。
所以我们可以采用自底向上的算法递推地给出所有符合条件的d(i, j)的值。

查询:
查询的巧妙之处是将[m, n]这段分成两个部分重叠的的区间
于是我们就可以把[m, n]分成两个(部分重叠的)长度为2^k的区间: [m, m+2^k-1], [n-2^k+1, n];

此题几个注意的地方:1. 要注意递推的时候按长度从2^0到2^j递推,j的循环要放在外面;2. log函数用的时候,里面参数是double;3. 求2的power是常用操作,使用左移<<操作非常合适;4. cin/cout会超时,要使用scanf/printf。

#include <iostream>

#include <cmath>



using namespace std;

#define LEN 50005

#define LOG_LEN 20

#define MAX(a,b) (a>b?a:b)

#define MIN(a,b) (a<b?a:b)

#define ABS(a) (a<0?-a:a)

const int INF (1<<30);



int cow[LEN];

int fmin[LEN][LOG_LEN];

int fmax[LEN][LOG_LEN];

int Q;

int N;



void init()

{

    memset(cow, 0, sizeof(cow));

    memset(fmin, 0, sizeof(fmin));

    memset(fmax, 0, sizeof(fmax));



    scanf("%d%d", &N, &Q);

    for (int i = 1; i <= N; i++)

    {

		scanf("%d", &cow[i]); 

    }

}



void build()

{

    // build the RMQ

    for (int i = 1; i <= N; i++)

    {

        fmin[i][0] = cow[i];

        fmax[i][0] = cow[i];

    }

    int size = int (log((double)(N + 1)) / log(2.0));

    

    for (int j = 1; j <= size; j++)

    {

        for (int i = 1; i + (1 << j) - 1 <= N; i++)

        {

            fmin[i][j] = MIN(fmin[i][j - 1], fmin[i + (1 << (j - 1))][j-1]);

            fmax[i][j] = MAX(fmax[i][j - 1], fmax[i + (1 << (j - 1))][j-1]);

        }

    }

}



int query(int left, int right)

{

    int diff = right - left + 1;

    int k = (int) (log((double)diff) / log(2.0));

    int min = MIN(fmin[left][k], fmin[right - (1 << k) + 1][k]);

    int max = MAX(fmax[left][k], fmax[right - (1 << k) + 1][k]);

    return max - min;

}



int main()

{

    init(); 

    build();

    

    // query

    for (int i = 0; i < Q; i++)

    {

        int x, y;

		scanf("%d%d", &x, &y);     

        printf("%d\n", query(x, y));  

    }

    return 0;

}

  

 

你可能感兴趣的:(poj)