s t st st表是一种用于解决 R M Q RMQ RMQ问题的工具, O ( n l o g n ) O(nlogn) O(nlogn)的时间建表,只要 O ( 1 ) O(1) O(1)的时间查询,可以很好地完成查询任务。但是美中不足的一点是, s t st st表不支持修改操作,因此有涉及修改的题目,请使用线段树或者其他数据结构。
s t st st表的建表方法
st表的表示方法
st表用
s
t
i
,
j
st_{i,j}
sti,j表示
[
j
,
j
+
i
2
−
1
]
[j,j+i^2-1]
[j,j+i2−1]中的区间最小值。
那么怎么进行建表呢?
首先
s
t
0
,
j
st_{0,j}
st0,j必定等于
a
j
a_j
aj
所以递推起点就出来了
那么怎么进行状态转移呢?
看下面这张图
应该很容易理解吧
上面大区间的最值,就是下面两个小区间的最值的最值。
因此,状态转移方程为
s
t
i
,
j
=
m
a
x
(
s
t
i
−
1
,
j
,
s
t
i
−
1
,
j
+
2
i
−
1
)
st_{i,j}=max(st_{i-1,j},st_{i-1,j+2^{i-1}})
sti,j=max(sti−1,j,sti−1,j+2i−1)
建表代码
for(int i=1;i<=n;++i){
scanf("%d",a+i);
lg[i]=lg[i/2]+1;//lg[i]为floor(log2(i))
}
for(int i=1;i<=31;++i)bi[i]=bi[i-1]*2;//bi[i]=2^i
for(int i=1;i<=n;++i){
st[0][i]=a[i];
}
for(int i=1;i<=lg[n];++i){
for(int j=1;j+bi[i]-1<=n;++j){
st[i][j]=max(st[i-1][j],st[i-1][j+bi[i-1]]);
}
}
查询方法
查询的方法其实也很简单
首先求出来一个值
即询问区间长度为
2
2
2的几次方
那也就是
l
g
lg
lg数组
设这个值为
t
t
t区间左右为
l
,
r
l,r
l,r
那么
t
=
l
g
[
r
−
l
+
1
]
t=lg[r-l+1]
t=lg[r−l+1]
同时
2
t
2^t
2t小于
[
l
,
r
]
[l,r]
[l,r]的长度
那么再来一张图
可以看出来要求的
[
l
,
r
]
[l,r]
[l,r]的区间最值就是两个小区间的最值的最值。(有重合也不会有影响)
因此查询方法为
scanf("%d%d",&l,&r);
t=lg[r-l+1];
printf("%d\n",max(st[t][l],st[t][r-bi[t]+1]));