您的位置:首页 > 其它

POJ 3264 Balanced Lineup(水题试ST算法模板)

2016-07-20 10:38 357 查看
题目链接:点击打开链接

查询区间最值问题,如果询问次数非常多,ST算法比线段树快(毕竟是O(1)查询)

但是现实是线段树用的比ST多(毕竟功能强大,也不会很慢)

 LCA问题提供了ST(在线)和Tarjan(离线)两种算法(。。。)

试水题。。。。。。。。。。。。。试ST算法模板。。。。。。。。。。。。。。。

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
using namespace std;
const int MAXN = 100100;
int n, query;
int A[MAXN];
int FMin[MAXN][20], FMax[MAXN][20];
/*
ST算法:基于动态规划求区间最值的算法。

分为预处理和查询两部分
O(nlogn)预处理 O(1)查询

预处理:定义 F[i][j] 为从 i开始到 i+2^j-1 区间内的最值 ,
我们可以讲这段2^j的区间分成两部分长度都为2^(j-1)的相同区间

区间1 为  i.....i+2^(j-1)-1   区间2为  i+2^(j-1).....i+2^j-1
那么可以得到  F[i][j] =Max( F[i][j-1],F[i+2^(j-1)][j-1],边界条件为F[i][0]=A[i].

由于大的区间是由小的区间得到的,所以预处理时必须按区间长度递增的顺序递推出F[i][j].

查询:求区间[ i , j ]的最值   令 d=(int) log2( j-i+1)
我们取靠i的长度为2^d区间 以及靠j的2^d区间内的最大值 ,两个区间内可以存在公共部分
则i,j max= Max ( F[i][d] ,F[j-2^d+1,d])

题意:要求找出区间内的最大最小值的差。
用两个数组分别保存区间最大和最小值
*/
void Init()
{
int i, j;
for (i = 1; i <= n; i++)
FMin[i][0] = FMax[i][0] = A[i];
for (i = 1; (1 << i) <= n; i++) //按区间长度递增顺序递推
{
for (j = 1; j + (1 << i) - 1 <= n; j++) //区间起点
{
FMin[j][i] = min (FMin[j][i - 1], FMin[j + (1 << (i - 1) )][i - 1]);
FMax[j][i] = max (FMax[j][i - 1], FMax[j + (1 << (i - 1) )][i - 1]);
}
}
}

int Query (int l, int r) //查询区间[l,r]最大值或最小值或最大最小值之差。。都可以。
{
int k = (int) (log (double (r - l + 1) ) / log ( (double) 2) );
return max (FMax[l][k], FMax[r - (1 << k) + 1][k]) - min (FMin[l][k], FMin[r - (1 << k) + 1][k]) ;
}
int main()
{
int i, a, b;
while (~scanf ("%d %d", &n, &query) )
{
for (i = 1; i <= n; i++) scanf ("%d", &A[i]);
Init();
for (int i = 1; i <= query; ++i)
{
scanf ("%d %d", &a, &b);
printf ("%d\n", Query (a, b) );
}
}
return 0;
}
参考资料:http://blog.csdn.net/u012350533/article/details/14645881
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj ST算法 模板