1. ST表
1.1. 功能
RMQ(Range Maximum/Minimum Query)
也就是查询区间的最值
注意:
1、只能查,不能修改
2、只能RMQ,不能区间和
1.2. 原理:动态规划,倍增
1.3. 操作
1.3.1. 建表
1.3.1.1. 定义:
st[i][j]
表示数组a[n]
中以
i
i
i为左端点,长度为
2
j
2^j
2j 的区间
考虑用动态规划实现
1.3.1.2. 转移方程
对于长度大于
1
1
1的区间
[
l
,
r
]
[l,r]
[l,r],都有
令
m
=
[
l
+
r
2
]
则
[
l
,
r
]
最小值
=
min
(
[
l
,
m
]
最小值
,
[
m
+
1
,
r
]
最小值
)
令m=[\frac{l+r}{2}]\\ 则[l,r]_{最小值}= \min([l,m]_{最小值}, [m+1,r]_{最小值})
令m=[2l+r]则[l,r]最小值=min([l,m]最小值,[m+1,r]最小值)
l r [l,r]最小值=3
| |
...3 5 4 9 8 5 6...
| | | | [l,m]最小值=3
l m m+1 r [m+1,r]最小值=5
3=min(3,5)
对于st[i][j]
,易知
l
=
i
r
=
i
+
2
j
−
1
m
=
[
l
+
r
2
]
=
[
2
i
+
2
j
−
1
2
]
=
i
+
2
j
−
1
−
1
l=i\\ r=i+2^j-1\\ m=[\frac{l+r}{2}] =[\frac{2i+2^j-1}2] =i+2^{j-1}-1
l=ir=i+2j−1m=[2l+r]=[22i+2j−1]=i+2j−1−1
故有
s
t
[
i
]
[
j
]
=
min
(
s
t
[
i
]
[
j
−
1
]
,
s
t
[
i
+
2
j
−
1
]
[
j
−
1
]
)
st[i][j]= \min(st[i][j-1],st[i+2^{j-1}][j-1])
st[i][j]=min(st[i][j−1],st[i+2j−1][j−1])
递推顺序:
由于算长度为
2
j
2^j
2j的区间要用到长度为
2
j
−
1
2^{j-1}
2j−1的区间,故外侧循环j从小到大,内层循环i遍历区间
1.3.1.3. 边界条件
当
j
=
0
j=0
j=0时,
2
j
=
1
2^j=1
2j=1,区间长度为
1
1
1,故
s
t
[
i
]
[
0
]
=
a
[
i
]
st[i][0]=a[i]
st[i][0]=a[i]
1.3.1.4. 复杂度
时间复杂度:
初始化,
O
(
n
)
O(n)
O(n)
递推,
O
(
n
l
o
g
2
n
)
O(nlog_2n)
O(nlog2n)
故总体
O
(
n
l
o
g
2
n
)
O(nlog_2n)
O(nlog2n)
空间复杂度:
st[i][j]
,
i
∈
[
0
,
n
−
1
]
i\in[0,n-1]
i∈[0,n−1],
j
∈
[
0
,
[
l
o
g
2
n
]
]
j\in[0,[log_2n]]
j∈[0,[log2n]],
故复杂度
O
(
n
l
o
g
2
n
)
O(nlog_2n)
O(nlog2n)
1.3.2. 查询
查询a
的区间
[
l
,
r
]
[l,r]
[l,r]的最小值
区间长度
l
e
n
=
r
−
l
+
1
len=r-l+1
len=r−l+1
令
j
=
[
l
o
g
2
l
e
n
]
j=[log_2len]
j=[log2len]
则
∵
j
≤
l
o
g
2
l
e
n
∴
2
j
≤
2
l
o
g
2
l
e
n
=
l
e
n
∵
j
+
1
>
l
o
g
2
l
e
n
∴
2
j
+
1
>
2
l
o
g
2
l
e
n
2
j
>
l
e
n
2
综上,
l
e
n
2
<
2
j
≤
l
e
n
\because j \le log_2len \\ \therefore 2^j \le 2^{log_2len}=len \\ \because j+1>log_2len \\ \therefore 2^{j+1}>2^{log_2len} \\ 2^j >\frac{len}2 \\ 综上,\frac{len}2<2^j \le len
∵j≤log2len∴2j≤2log2len=len∵j+1>log2len∴2j+1>2log2len2j>2len综上,2len<2j≤len
因此,区间
[
l
,
l
+
2
j
−
1
]
∪
[
r
−
2
j
+
1
,
r
]
[l,l+2^j-1]\cup[r-2^j+1,r]
[l,l+2j−1]∪[r−2j+1,r]就是区间
[
l
,
r
]
[l,r]
[l,r]
...3 5 4 9 8 5 6...
| | |
l m r min=3
3 5 4 9
| |
l l+2^j-1 min=3
9 8 5 6
| |
r-2^j+1 r min=5
3=min(3,5)
若
A
∪
B
=
C
A\cup B=C
A∪B=C,则
m
i
n
(
m
i
n
(
A
i
)
,
m
i
n
(
B
i
)
)
=
m
i
n
(
C
i
)
min(min(A_i),min(B_i))=min(C_i)
min(min(Ai),min(Bi))=min(Ci)
(另外,区间和没有该性质,故st表不能解决区间和问题)
C _________________
A ___________
B ___________
因此,要求的区间
[
l
,
r
]
[l,r]
[l,r]的最小值就是求
min(
区间
[
l
,
l
+
2
j
−
1
]
[l,l+2^j-1]
[l,l+2j−1]的最小值,
区间
[
r
−
2
j
+
1
,
r
]
[r-2^j+1,r]
[r−2j+1,r]的最小值
)
而以上两个区间长度都是
2
k
(
k
∈
N
∗
)
2^k(k\in N*)
2k(k∈N∗),故可以直接查st获取最小值,时间复杂度
O
(
1
)
O(1)
O(1)
1.4. 实现
//2^x
inline int pw2(int x){
return 1<<x;
}
int st[N][LOG_N];
int log2[N];
//初始化
inline void init(){
//计算log2
for(int i=1,x=0;i<=n;i++){
if(i==(1<<(x+1))){
x++;
}
log2[i]=x;
}
//边界条件
for(int i=0;i<n;i++){
st[i][0]=a[i];
}
//递推
for(int i=1,x=1;i<=log2[n];i++,x<<=1){
//x=2^(i-1)
int l=0,m=l+x-1,r=m+x;
while(r<n){
st[l][i]=min(st[l][i-1],st[mid+1][i-1]);
l++;m++;r++;
}
}
}
//查询
inline int query(int l,int r){
int j=log2[r-l+1];
return min(st[l][j],st[r-pw2(j)+1][j]);
}