RMQ的ST算法

//poj 3264 Balanced Lineup
#include<iostream> //ST算法,即(Sparse_Table ,稀疏表),可以在O(nlogn)的预处理以后,实现O(1)的查询效率
#include <cmath>
using namespace std;
const int max_n=50005;
int arr[max_n],n,t,l,r; //原数列arr从下标1开始
int rmq_m[max_n][16],rmq_n[max_n][16]; //16>=log2(50000)
//rmq_m[i][j],rmq_n[i][j]分别表示原数列arr[i, i+2^j - 1]区间中的最大值和最小值,区间长度为2^j
void rmq_init() //预处理,采用DP
{
int i,j;
for(i=1;i<=n;++i)
rmq_m[i][
0]=rmq_n[i][0]=arr[i];
for(j=1;j<=log(n+0.0)/log(2.0);++j) //j表示区间长度为2^j,区间范围[i, i+2^j - 1],小于等于n,所以 j<=log(n+0.0)/log(2.0)
{
for(i=1;i+(1<<j)-1<=n;++i) //因为rmq_m[i][j]表示arr[i, i+2^j - 1]的最大值,所以 i+2^j - 1 <= n
{
rmq_m[i][j]
=max(rmq_m[i][j-1],rmq_m[i+(1<<(j-1))][j-1]);
rmq_n[i][j]
=min(rmq_n[i][j-1],rmq_n[i+(1<<(j-1))][j-1]);
}
}
}
//DP的初值:rmq_m[i][0]其实就等于arr[i]; 状态转移方程:rmq_m[i][j]=max(rmq_m[i][j-1],rmq_n[i+2^(j-1)][j-1])
//采用自底向上的算法递推地给出所有符合条件的rmq_m[i][j]的值

int rmq(int a,int b) //查询
{
int m=log(b-a+1.0)/log(2.0);
int x=max(rmq_m[a][m],rmq_m[b-(1<<m)+1][m]); //区间[a,b]最大值
int y=min(rmq_n[a][m],rmq_n[b-(1<<m)+1][m]);
return x-y;
}
//查询从a到b这一段的最大(小)值, 那么我们先求出一个最大的整数m, 使得m满足2^m <= (b - a + 1).
//于是我们就可以把[a, b]分成两个长度为2^m的区间: [a, a+2^m -1], [b-2^m +1, b]; (有部分重叠,b-2^m +1 <= a+2^m -1)
//而rmq_m[a][m]为[a, a+2^m-1]的最大值, rmq_m[b-2^m +1][m]为[b-2^m +1, b]的最大值
int main()
{
scanf(
"%d%d",&n,&t);
for(int i=1;i<=n;++i)
scanf(
"%d",arr+i);
rmq_init();
while(t--)
{
scanf(
"%d%d",&l,&r);
printf(
"%d\n",rmq(l,r));
}
return 0;
}

  

posted on 2011-08-24 16:02  sysu_mjc  阅读(339)  评论(0编辑  收藏  举报

导航