POJ 3264 Balanced Lineup (ST算法入门)

转载请注明出处,谢谢http://blog.csdn.net/acm_cxlove/article/details/7854526       by---cxlove

题目:查询区间的最大值和最小值

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

以前只会线段树的做法,nlgn的建树,lgn的查询。

因为RMQ作为一种题目常见的问题,有必须学习一下,可以作为一个工具出现。

ST算法是另外一种高效的求解区间最值的算法。nlgn的处理,可以达到o(1)的查询,而且线段树的常数也是非常大的。

它是一种动态规划的方法。 
以最小值为例。a为所寻找的数组. 
用一个二维数组f(i,j)记录区间[i,i+2^j-1](持续2^j个)区间中的最小值。其中f[i,0] = a[i]; 
所以,对于任意的一组(i,j),f(i,j) = min{f(i,j-1),f(i+2^(j-1),j-1)}来使用动态规划计算出来。 
这个算法的高明之处不是在于这个动态规划的建立,而是它的查询:它的查询效率是O(1). 
假设我们要求区间[m,n]中a的最小值,找到一个数k使得2^k
这样,可以把这个区间分成两个部分:[m,m+2^k-1]和[n-2^k+1,n].我们发现,这两个区间是已经初始化好的. 
前面的区间是f(m,k),后面的区间是f(n-2^k+1,k). 
这样,只要看这两个区间的最小值,就可以知道整个区间的最小值! 

#include
#include
#include
#include
#include
#define N 100005
using namespace std;
int n,q,a[N];
int mx[N][18],mn[N][18];
void Rmq_Init(){
	int m=floor(log((double)n)/log(2.0));
	for(int i=1;i<=n;i++) mx[i][0]=mn[i][0]=a[i];
	for(int i=1;i<=m;i++)
		for(int j=n;j;j--){
			mx[j][i]=mx[j][i-1];
			mn[j][i]=mn[j][i-1];
			if(j+(1<<(i-1))<=n){
				mx[j][i]=max(mx[j][i],mx[j+(1<<(i-1))][i-1]);
				mn[j][i]=min(mn[j][i],mn[j+(1<<(i-1))][i-1]);
			}
		}
}
int Rmq_Query(int l,int r){
	int m=floor(log((double)(r-l+1))/log(2.0));
	int Max=max(mx[l][m],mx[r-(1<


你可能感兴趣的:(ACM_杂物)