【poj3264】 Balanced Lineup

http://poj.org/problem?id=3264 (题目链接)

题意

  给出序列,求区间最大值-最小值

Solution

  无修改,询问较多,ST表水一发。

ST算法(Sparse Table):

  它是一种动态规划的方法。以最小值为例。a为所寻找的数组,用一个二维数组 f(i,j) 记录区间 [i,i+2^j-1] 区间中的最小值。其中 f[i,0] = a[i] ; 所以,对于任意的一组 (i,j),f(i,j) = min{ f(i,j-1),f(i+2^(j-1),j-1)} 来使用动态规划计算出来。

  这个算法的高明之处不是在于这个动态规划的建立,而是它的查询:它的查询效率是O(1)!如果不细想的话,怎么弄也是不会想到有O(1)的算法的。

  假设我们要求区间[m,n]中a的最小值,找到一个数k使得2^k<n-m+1,即k=[ln(b-a+1)/ln(2)] 这样,可以把这个区间分成两个部分:[m,m+2^k-1]和[n-2^k+1,n]!我们发现,这两个区间是已经初始化好的!前面的区间是f(m,k),后面的区间是f(n-2^k+1,k)!这样,只要看这两个区间的最小值,就可以知道整个区间的最小值!

代码

// poj3264
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 2147483640
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=50010;
int bin[30],a[maxn],mn[maxn][30],mx[maxn][30];
int n,m;

void build() {
	for (int i=1;i<=n;i++) mx[i][0]=mn[i][0]=a[i];
	for (int j=1;j<=20;j++)
		for (int i=1;i+bin[j]<=n+1;i++)
			mn[i][j]=min(mn[i][j-1],mn[i+bin[j-1]][j-1]);
	for (int j=1;j<=20;j++)
		for (int i=1;i+bin[j]<=n+1;i++)
			mx[i][j]=max(mx[i][j-1],mx[i+bin[j-1]][j-1]);
}
int query(int l,int r) {
	int x=log(r-l+1)/log(2);
	int a=max(mx[l][x],mx[r-bin[x]+1][x]);
	int b=min(mn[l][x],mn[r-bin[x]+1][x]);
	return a-b;
}
int main() {
	bin[0]=1;for (int i=1;i<=20;i++) bin[i]=bin[i-1]<<1;
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	build();
	for (int x,y,i=1;i<=m;i++) {
		scanf("%d%d",&x,&y);
		printf("%d\n",query(x,y));
	}
	return 0;
}

  

posted @ 2016-10-09 19:51  MashiroSky  阅读(161)  评论(0编辑  收藏  举报