POJ 3264 Balanced Lineup ST算法

ST算法即是sparse table算法,就是稀疏表的意思,就是利用二分法来划分一个表,划分为2的次方段,之后利用这个st表计算查询结果,可以使得预处理时间O(nlgn),而查询时间为O(1) ;


那么有人会有疑问,既然查询时间是O(1),那么为什么这个算法很多时候并不比线段树快多少,甚至根本没有快过呢?

因为其实查询时间为O(log(range)), range为查询区间的大小,因为要找到range二进制的最高位数,可以使用floor(log(range))的数学方法查找这个数,不过也是需要lg(rang)的时间效率,因为range不算太大,故此这点时间效率可以认为是O(1).不过这就解析了为什么这个算法的查询时间不比线段树快多少,因为线段树的查询时间就是log(range)。

网上很少人指出指点,一般都是笼统地说查询时间是O(1), 好像也不少人为此感到疑惑,故此解析下。

不过也可以这么说算法本身的查询时间效率是O(1),而实际执行起来却是 O(logn)。或者说理论上的时间效率是O(1),实际时间效率是O(logn)。估计这就是为什么很多大牛的博客或者一些书本上也是写这个算法的查询效率是O(1)了。


说到底就是一个数学方法计算。

具体可以参考topcoder或者参考这个大牛的吧:http://blog.csdn.net/v_july_v/article/details/18312089


本算法的优势就是代码量会比线段树省点。掌握了其中的数学原理之后,这个算法还是很好写的。

不过有线段树的存在,那么这个算法好像也不是必不可少的。


#include <cstdio>
#include <algorithm>

const int MAX_N = 50001;
const int L = 17;//16;//(int)log(MAX_N) / log(2) + 1;
int N, Q, A, B;
int maxArr[MAX_N][L], minArr[MAX_N][L];

void initRMQ_ST()
{
	for (int j = 1; j < L; j++)
		for (int i = 1; i <= N; i++)
		{
			if (i - 1 + (1<<j) <= N)
			{
				maxArr[i][j]=max(maxArr[i][j-1], maxArr[i+(1<<(j-1))][j-1]);
				minArr[i][j]=min(minArr[i][j-1], minArr[i+(1<<(j-1))][j-1]);
			}
			else break;//可以break掉
		}
}

inline int query(int low, int up)
{
	int range = up - low + 1;
	int r = 0;
	while ((1<<(r+1)) <= range) r++;
	int maxV = max(maxArr[low][r], maxArr[up-(1<<r)+1][r]);
	int minV = min(minArr[low][r], minArr[up-(1<<r)+1][r]);
	return maxV - minV;
}

int main()
{
	while (scanf("%d %d", &N, &Q) != EOF)
	{
		for (int i = 1; i <= N; i++)
		{
			scanf("%d", &maxArr[i][0]);
			minArr[i][0] = maxArr[i][0];
		}
		initRMQ_ST();
		while (Q--)
		{
			scanf("%d %d", &A, &B);
			printf("%d\n", query(A, B));
		}
	}
	return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值