s t 表 的 算 法 详 解 st表的算法详解 st表的算法详解
st表主要用来解决区间最值问题,他是基于倍增的思想,使得时间复杂度只有
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn),查询为
O
(
1
)
O(1)
O(1)。
首先,我们需要维护一个数组
s
[
i
]
[
j
]
s[i][j]
s[i][j],这个数组的含义是从
i
i
i到
i
+
2
j
−
1
i +2^j-1
i+2j−1的区间最小值。如果我们使用倍增的思想,很显然,我们需要考虑
s
[
i
]
[
j
]
s[i][j]
s[i][j]数组的转移。
我们不妨这样思考,对于一段区间内的最小值,一定是前半区间的最小值和后半区间最小值再取
m
i
n
min
min,所以思路就来了,我们可以很轻松的得到转移公式。
s
[
i
]
[
j
]
=
m
i
n
(
s
[
i
]
[
j
−
1
]
,
s
[
i
+
2
j
−
1
]
[
j
−
1
]
)
s[i][j] = min(s[i ][j -1], s[i +2^{j -1}][j-1])
s[i][j]=min(s[i][j−1],s[i+2j−1][j−1])
说实话这个思路一开始不好想,但是如果你学过LCA的话,你应该会比较熟悉这种转移方法。LCA的
f
a
fa
fa数组的转移如下:
for(int j = 1; j <= 20; j ++ )
fa[i][j] = fa[fa[i][j - 1]][j - 1]
得到了上述转移公式之后,我们还需要思考怎样
O
(
1
)
O(1)
O(1)的时间内查询一段区间的最小值。
假设输入的区间为
[
L
,
R
]
[L,R]
[L,R],不妨设
t
=
⌊
l
o
g
(
R
−
L
+
1
)
⌋
t=\left \lfloor log(R-L+1)\right \rfloor
t=⌊log(R−L+1)⌋则
s
[
L
]
[
t
]
和
s
[
R
−
2
t
]
[
t
]
s[L][t]和s[R-2^t][t]
s[L][t]和s[R−2t][t]一定把整个区间覆盖了,而且
{
[
L
,
L
+
2
t
]
⋃
[
R
−
2
t
+
1
,
R
]
}
⊆
{
[
a
,
b
]
∣
L
≤
a
≤
b
≤
R
}
\{[L,L+2^t]\bigcup[R-2^t+1, R]\}\subseteq \{[a, b]|L\le a\le b \le R\}
{[L,L+2t]⋃[R−2t+1,R]}⊆{[a,b]∣L≤a≤b≤R}。从而实现了
O
(
1
)
O(1)
O(1)查找。
全部的代码如下:
//referece https://www.acwing.com/problem/content/1275/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2 * 1e5 + 10;
int f[maxn][21];
int a[maxn];
int n, m;
int main()
{
cin >> n;
for(int i = 1; i <= n; i ++ ) cin >> f[i][0];
int M = log2(n);
for(int k = 1; k <= M; k ++ )
{
for(int i = 1; i + (1 << k) - 1 <= n; i ++ )
{
f[i][k] = max(f[i][k - 1], f[i + (1 << k - 1)][k - 1]);
}
}
cin >> m;
while(m -- )
{
int l, r;
cin >> l >> r;
int p = log2(r - l + 1);
cout << max(f[l][p], f[r - (1 << p) + 1][p]) << endl;
}
}