ST表

ST表是什么:

st表其实就是一个二维数组,利用了倍增的思想。st[i][j]维护区间[i,i+2^j-1]内的最大值或最小值。

ST表一般用来干什么:

st表一般用来解决RMQ(区间最值)问题,但是不支持修改操作。如果需要修改,请直接用线段树。

时间复杂度预处理查询
st表O(nlgn)O(1)
线段树O(nlgn)O(lgn)

怎么构建ST表:

前面已经提到过,st[i][j]维护区间[i,i+2^j-1]内的最大值或最小值,而区间[i,i+2^j-1]可以分成两部分来表示,即:[i,i+2^(j-1)-1]和[i+2^(j-1),i+2^(j-1)+2^(j-1)-1],其分别对应st[i][j-1]和st[i+2^(j-1)][j-1],因此若维护的是区间最大值,我们可以得到一个状态转移方程:st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]),那么就有了初始化操作:(至于上界的设置 我们下面再解释)

inline void init()
{
	int MAX=log2(n);
	for(int i=1;i<=n;i++)
		st[i][0]=a[i];//2^0-1=0 即st[i][j]维护的是区间[i,i]的值 即本身
	for(int j=1;j<=MAX;j++)//外层循环是j
		for(int i=1;i<=n;i++)
			if(i+(1<<j)-1<=n)
				st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}

可以加一个小优化:

inline void init()
{
	int MAX=log2(n);
	for(int i=1;i<=n;i++)
		st[i][0]=a[i];//2^0-1=0 即st[i][j]维护的是区间[i,i]的值 即本身
	for(int j=1;j<=MAX;j++)//外层循环是j
	{
		for(int i=1;i<=n;i++)
		{
			if(i+(1<<j)-1<=n)
				st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
			else
				break;
		}
	}
}

 

 怎么查询:

先看一个定理,2^(log2(a))>a/2。(log2(a)是向下取整的)这个还是比较好证明的,我们设a=2^(k-1),b=2^k,那么log2(a)=k-1,log2(b)=k,显然对于a和b都满足上式,那么对于区间(a,b)的所有数x,均有log(x)=k-1,那么2^(log2(x))=2^(k-1)=a,而b=2*a,有x<b,即x/2<a,也即2^(log2(x))=a>x/2。有了这个结论就好办了。我们设要查询的区间的左右端点分别为l和r,那么该区间长度len=r-l+1,由上述结论我们得:2^(log2(len))>len/2,若设t=log2(len),那么区间[l,l+(1<<t)-1]和[r-(1<<t)+1,r]就可以完全覆盖区间[l,r],那么区间[l,r]的最大值就等于:max(st[l][t],st[r-(1<<t)+1][t])

inline void query(int l,int r)
{
	int len=r-l+1;
	int t=log2(len);	//2^(log2(a))>a/2
	printf("%d\n",max(st[l][t],st[r-(1<<t)+1][t]));
}

就这么多了~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值