poj 3264 Balanced Lineup

RMQ模板题,用ST算法

//DP预处理
//dp[i][j] 表示从下标i开始,长度为2^j的最大值
//状态转移方程 dp[i][j] = max{ dp[i][j-1] , dp[i+2^(j-1)][j-1] }
//也就是一个长度为2^j的区间,二分为两个2^(j-1)的长度
//对于查询[a,b]以内的最大值,先求出区间长度LEN = b-a+1
//查询结果为 res = max{dp[a][k] , dp[b-2^k+1][k]} , 关键是k,是什么,怎么计算
//当满足 2^k >= LEN/2  , 且k最小时,这个k就是我们要的值
//k可以用计算公式一步算得 : k = (int) (log((double)(b-a+1))/log(2.0))
//另外一个问题,对于构建dp值的时候,dp[i][j],这个j最大去到多少?
//道理是一样的,对于总区间,长度为L,同样是 2^j >= L/2 , 取最小的j就是我们要的值
//所以也可以用公式一步计算出来  j = (int) (log((double)L) / log(2.0))

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
#define N 50010
#define M 20

int n,m,a[N],dp[N][M],__dp[N][M];

void TEST()
{
    cout << "最大值" << endl;
    int K = (int) (log((double)n) / log(2.0));
    for(int i=1; i<=n; i++)
        for(int j=0; j<=K; j++)
            printf("dp[%d,%d] = %d\n",i,j,dp[i][j]);
    cout << "最小值" << endl;
    for(int i=1; i<=n; i++)
        for(int j=0; j<=K; j++)
            printf("__dp[%d,%d] = %d\n",i,j,__dp[i][j]);

}

void ST()
{
    for(int i=1; i<=n; i++)
        dp[i][0] = __dp[i][0] = a[i];

    int K = (int) (log((double)n) / log(2.0));
    for(int j=1; j<=K; j++)
        for(int i=1; i+(1<<j)-1 <= n; i++)
        {
            int k = i+(1<<(j-1));
            dp[i][j] = max( dp[i][j-1] , dp[k][j-1] );
            __dp[i][j] = min( __dp[i][j-1] , __dp[k][j-1]);
        }
}

int RMQ(int x ,int y)
{
    int K = (int) (log((double)(y-x+1)) / log(2.0));
    int k = y-(1<<K)+1;
    int Max = max( dp[x][K] , dp[k][K]);
    int Min = min( __dp[x][K] , __dp[k][K]);
    return Max - Min;
}

int main()
{
    while(cin >> n >> m)
    {
        for(int i=1; i<=n ;i++) cin >> a[i];
        ST();
        //TEST();
        while(m--)
        {
            int x,y;
            cin >> x >> y;
            int res = RMQ(x,y);
            cout << res << endl;
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/scau20110726/p/3096722.html