st 表是倍增的产物
st表可以维护区间极值(目前我也就只知道维护区间极值,所以这篇博客也就只讲极值)
——————————————————————————————————————
st表实际上就是优化状态的一种方式,
因为我们把两个长度相等区间合并其实可以知道合并后区间的长度,
我们可以通过区间长度代替一个难枚举的量,比如区间端点,
这时在优化区间长度,因为电脑用2进制可以O(1)求出,所以如果长度是二进制的话,那么就很容易维护区间极值了
——————————————————————————————————————
实现
- 定 义 s t [ l ] [ j ] 为 [ l ] [ l + 2 j − 1 ] 的 极 值 定义st[l][j] 为 [l][l+2^j-1]的极值 定义st[l][j]为[l][l+2j−1]的极值
-
转
移
,
[
l
,
l
+
2
j
−
1
]
的
极
值
实
际
上
是
[
l
,
l
+
2
j
−
1
−
1
]
与
[
l
+
2
j
−
1
,
l
+
2
j
−
1
]
的
最
大
值
或
最
小
值
,
这
两
区
间
的
长
度
的
长
度
都
是
2
j
−
1
,
所
以
s
t
[
l
]
[
j
]
=
m
a
x
/
m
i
n
(
s
t
[
l
]
[
j
−
1
]
,
s
t
[
l
+
(
1
<
<
(
j
−
1
)
)
]
[
j
−
1
]
)
转移,[l,l+2^j-1]的极值实际上是[l,l+2^{j-1}-1]与[l+2^{j-1},l+2^{j}-1] 的最大值或最小值,这两区间的长度的长度都是2^{j-1},所以st[l][j]=max/min(st[l][j-1],st[l+(1<<(j-1))][j-1])
转移,[l,l+2j−1]的极值实际上是[l,l+2j−1−1]与[l+2j−1,l+2j−1]的最大值或最小值,这两区间的长度的长度都是2j−1,所以st[l][j]=max/min(st[l][j−1],st[l+(1<<(j−1))][j−1])
———————————————————————————————————
例题:
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int st[N][20],a[N];//st[l][j]表示[l,l+2^j-1]的极值
int n,T;
int main(){
scanf("%d%d",&n,&T);
for(int i=1;i<=n;i++) {scanf("%d",&a[i]);st[i][0]=a[i];}
int up=log2(n);
for(int j=1;j<=up+2;j++)//这里尤其要注意,因为后面需要以长度作为更新的量,所以要先枚举区间长度,这样就可以确保
//扫到长度大的区间的时候已经得知小区间的值了
for(int l=1;l<=n&&(l+(1<<j)-1<=n);l++)
{
int r=(l+(1<<j)-1);
st[l][j]=max(st[l][j-1],st[l+(1<<(j-1))][j-1]);
}
while(T--){
int l,r;
scanf("%d%d",&l,&r);
int len=(log2(r-l+1));
int ans=max(st[l][len],st[r-(1<<len)+1][len]);
printf("%d\n",ans);
}
}
本质是倍增,其实是dp优化, O ( n 2 ) 到 O ( n l o g n ) 的 优 化 体 会 到 了 吗 ? O(n^{2})到O(nlogn)的优化体会到了吗? O(n2)到O(nlogn)的优化体会到了吗?