ST表-笔记

ST表

用途:N个数,M次询问,每次给定区间[L, R],求区间最大值
(不支持在线修改,是一种离线算法)

要求:O(1) 时间内求区间最大值
设原数组为 a[]
方案:利用倍增思想,倍数为2
f(i, j)表示区间[i, i+ 2 j 2^j 2j],即下标 i 开始的 2 j 2^j 2j 个数组成的区间。
由定义得:f(i, 0) = a[i]; 这个边界条件
一般的转移:把一个区间分成两半 f ( i , j ) = m a x ( f ( i , j − 1 ) , f ( i + 2 j − 1 , j − 1 ) ) f(i, j) = max(f(i, j-1), f(i+2^{j-1}, j-1)) f(i,j)=max(f(i,j1),f(i+2j1,j1))

(1)预处理:

算出所有f(i, j),i 和 a.size() 有关系,j 最大为log(a.size()),因此时间复杂度为O(nlogn)。存储结构用二维数组st[i][j],根据ij的范围,空间复杂度也是O(nlogn)。

for(int i = 0; i < n; ++i)
	st[i][0] = a[i];
for(int j = 1; (1 << j) <= n; ++j){
	for(int i = 0; i+(1 << j) <= n; ++i)
		st[i][j] = max(st[i][j-1], st[i+(1 << (j-1))][j-1]);
}// st表的初始化

在这里插入图片描述
预处理的顺序为列先算,从左到右
原因:st[i][j] = max(st[i][j-1], st[i+(1 << (j-1))][j-1]);
由递推式看出,算某个元素,需要已知它上一列同一行的元素,以及上一列的下面某一行的元素。例:上图 橙色 = max(绿色, 蓝色);

(2) 查询:

初始化时,每一个状态对应的区间长度都为2的整数次幂( 2 j 2^j 2j),由于给出的查询区间长度不一定恰好为 2 j 2^j 2j
因此我们可以求两个重叠的区间的最值,即求出了这个区间的最值,具体如下:
查询[L, R]区间最值,则求[L, k],[R-k+1, R]的最值,而这两个区间必须要重叠,因此要满足k > (L+R)/2。
如何确定k?我们发现 2 l o g ( l e n ) > l e n / 2 2log(len) > len/2 2log(len)>len/2,len为区间长度。而恰好 2 l o g ( l e n ) 2log(len) 2log(len的长度满足作为st表f(i, j)的区间长度的条件,因此 2 l o g ( l e n ) 2log(len) 2log(len可作为k值。接下来证明 2 l o g ( l e n > l e n / 2 2log(len > len/2 2log(len>len/2
向下取整 [ 2 l o g ( l e n ) 」 < = l e n [2log(len)」<= len [2log(len)<=len,当len刚好是2的整数幂时,不等式取等, l e n > l e n / 2 len > len/2 len>len/2自然成立;取小于号的时候,设 [ 2 l o g ( l e n ) 」 = = l e n 2 < l e n , [2log(len)」== len2 < len, [2log(len)==len2<len 2 l o g ( l e n 2 ) = = l e n 2 2log(len2)== len2 2log(len2)==len2,此时len2是比len小的最大的一个2的整数幂。写成二进制:
Len:000010…010…0
Len2: 000010…0
Len2是2的幂次,某一位为1,len比len2稍大一些,该位也是1,并且在右边也会有若干个1,len/2相当于右移1位,发现 l e n / 2 < l e n 2 len/2 < len2 len/2<len2,因此
[ 2 l o g ( l e n ) = = l e n 2 > l e n / 2 [2log(len)== len2 > len/2 [2log(len)==len2>len/2

int search(int l, int r){
    int k = (int)(log((double)(r - l + 1)) / log(2.0));//	换底公式,将底换成2 
    return max(st[l][k],st[r - (1 << k) + 1][k]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值