在RMQ问题(区间最值问题) 中 , ST 算法就是倍增的产物 。给定一个长度为N的数列 A ,ST算法能在 

ST 算法_区间最值

 时间的预处理后,以O(1)的时间复杂度在线回答" 数列 A 中下标在 l ~ r 之间最大的值是多少" ,这样的区间最值问题 。设 

ST 算法_区间最值_02

 表示数列A 中下标在子区间 

ST 算法_区间最值_03

里的数的最大值 ,也就是从 i 开始的 

ST 算法_i++_04

 个数的最大值。递推边界显然是

ST 算法_预处理_05

  , 即数列 A 在子区间 [ i,j ] 里的最大值 。在递推时,我们把子区间的长度成倍的增长 ,有公式 

ST 算法_i++_06

 ,即长度为 

ST 算法_i++_04

 的子区间的最大值是左右两半长度为 

ST 算法_预处理_08

 的子区间的最大值中的较大的一个。

// 区间最值
void ST_prework() { // st算法预处理
for(int i = 1 ;i<=n ; i++ ) {
f[i][0] = a[i] ; // 处理边界 [i,i] 的最大值就是 a[i]
}
int t = log(n)/log(2) + 1 ; // 这里是枚举右端点
for(int j =1 ; j<t ; j++){
for(int i = 1 ;i<=n-(1<<j)+1 ;i++) {
// f[i][j] = max(f[i][j-1] ,f[i+(1<<(j-1))][j-1]) ;
f[i][j] = min(f[i][j-1] ,f[i+(1<<(j-1))][j-1]) ;
}
}

}

 

当询问任意区间 [  L, R ] 的最值时, 我们先计算出一个 k  ,满足 

ST 算法_区间最值_09

 ,也就是使2 的k 次幂小于区间长度的前提下的最大 k 。那么, " 从 l 开始的

ST 算法_i++_10

 个数" 和"以 r 结尾的

ST 算法_i++_10

个数"这两段一定覆盖了整个区间 [ l,r ] ,这两段的最大值分别是 F[l,k] 和 F[r-2^k +1 , k] ,二者中较大的那个就是整个区间的最值。

 

int ST_query(int l ,int r){ // 查询 区间 [l,r] 之间的最值
int k = log(r-l+1)/log(2);
return max(f[l][k],f[r-(1<<k)+1][k]) ;
}