图解ST表

st表用来维护静态区间最值非常有效快捷的方法,但是只要取最值的数需要改变,那么st表便变得无用,你需要转去研究下线段树了。那么下面来看看初看不好理解,但是超好写的st表模板求最大或最小值。
问题:给出长度为N的数组,存放于data[ ]数组中,每次询问区间最大值,没有修改。
空间上需要准备一个二维数组a[i][j]用以存储以i为起点的2j个元素的最大值。如a[3][0]存储的就是以第3个元素为起点的20个元素的最大值,这个是就是data[3],那么a[3][3]存储的便是以第3个元素为起点的2^3个元素的最大值.
这里写图片描述
因此st表里初始化的时候,i为起点的2j个元素的最大值便是由上图中蓝色和黄色两个部分中最值取最大值,这两部分起点分别是i和i+2(j-1),因此便有如下的递推式:
a[i][j] = max(a[i][j-1],a[i+(1 << (j-1))][j-1]);
那么当所有的最大值记录到了a数组中后,下面便是查询最值了。假设查询的区间是[x,y],那么你需要找到那个k,让以x为起点的2k个元素和以y为终点的2k个元素的两个区间的叠加中的最大值。那么这个k的取值需要能让这样两个区间能重叠,如下图所示:
这里写图片描述
因此令k为满足2^k <= y - x +1的最大整数 ,查询[x ,y]的最值为
max(a[x][k],a[y-(1 << k)+1][k]).
上面便是对st表的初始化和查询的解释分析。下面上标程:

#include<iostream>
#define MAXN 100010
using namespace std;
int n,m;
int a[MAXN][18];
int main()
{
	cin >> n >> m;
	for(int i=1;i<= n; i++)
	{
		scanf("%d",&a[i][0]);
	}
	for(int j = 1;(1<<j) <= n; j++)  //st表初始化
	{
		for(int i = 1; i + (1<<j)-1 <=n; i++)
		{
			a[i][j] = max(a[i][j-1],a[i+(1<<(j-1))][j-1]);
		}
	} 
	int x,y,k;
	for(int i = 1; i<= m; i++)//共m条询问
	{
		scanf("%d%d",&x,&y);
		//查询操作,查询[x,y]范围内的最大值
		/*暴力求K
		k = 0;
		while((1<< (k+1)) <= y - x + 1 )k++;
		*/
		//数学公式log(a)b = log(10)b / log(10)a
		k = log(y-x+1) / log(2);
		printf("%d\n",max(a[x][k],a[y-(1<<k)+1][k]));
	} 
	return 0;
}
/*建议大家做
POJ 3264 	Balanced Lineup
POJ 3368 	Frequent values 
*/
  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值