题目链接
http://poj.org/problem?id=3264
题目意为给定一串数组,求某个区间范围内的最大值和最小值之差。
由于询问数量较多,并且也不涉及更新值,所以使用st求RMQ预处理最大和最小。
此题用来学习ST算法,j表示包含i的i后2^j个数的最大值,可以知道,dp[i][j]可以被拆分成两部分dp[i][j - 1]和dp[i + (1<<(j - 1))][j - 1]这样就可以更新出所有的dp。询问时只要求出一个最大的j使y - x + 1大于2^j即可将询问拆分成dp[x][j]和dp[y - (1<< j) + 1][j]。o(1)查询就实现了。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define rep(i, s, t) for(int i = s;i <= t;i++)
#define rap(i, s, t) for(int i = s;i >= t;i--)
using namespace std;
int n, q;
int a[50004];
int maxx[50004][32], minx[50004][32];
void ST(int n)
{
rep(i, 1, n){
maxx[i][0] = minx[i][0] = a[i];
}
int k = log(n * 1.0) / log(2.0);
rep(j, 1, k){
rep(i, 1, n){
if(i + (1<<(j - 1)) > n) break;
maxx[i][j] = max(maxx[i][j - 1], maxx[i + (1<<(j - 1))][j - 1]);
minx[i][j] = min(minx[i][j - 1], minx[i + (1<<(j - 1))][j - 1]);
}
}
}
int get_Ans(int x, int y)
{
int k = log(y - x + 1.0) / log(2.0);
return max(maxx[x][k], maxx[y - (1<<k) + 1][k]) - min(minx[x][k], minx[y - (1<<k) + 1][k]);
}
int main()
{
while(cin>>n>>q)
{
rep(i, 1, n){
scanf("%d", &a[i]);
}
memset(maxx, 0, sizeof(maxx));
memset(minx, 0, sizeof(minx));
ST(n);
rep(i, 1, q){
int st, en;
scanf("%d%d", &st, &en);
printf("%d\n", get_Ans(st, en));
}
}
return 0;
}