ST表用来解决区间最值问题(也可以解决区间gcd)
利用倍增的思想,
O
(
n
log
2
n
)
O\left(n\log_2 n\right)
O(nlog2n)预处理,
O
(
1
)
O\left(1\right)
O(1)区间查询
令
f
(
i
,
j
)
f\left(i,j\right)
f(i,j)表示区间
[
i
,
i
+
2
j
−
1
]
\left[i,i+2^j-1\right]
[i,i+2j−1]
f
(
i
,
0
)
=
a
i
f\left(i,0\right) = a_i
f(i,0)=ai
f
(
i
,
j
)
=
max
(
f
(
i
,
j
−
1
)
,
f
(
i
+
2
j
−
1
,
j
−
1
)
)
f\left(i,j\right) = \max\left(f\left(i,j-1\right), f\left(i+2^{j-1},j-1\right)\right)
f(i,j)=max(f(i,j−1),f(i+2j−1,j−1))
对于查询
[
l
,
r
]
\left[l,r\right]
[l,r],令
s
=
⌊
log
2
(
r
−
l
+
1
)
⌋
s = \left\lfloor \log_2\left(r-l+1\right) \right\rfloor
s=⌊log2(r−l+1)⌋
通过
max
(
f
[
l
,
l
+
2
s
−
1
]
,
f
[
r
−
2
s
+
1
,
r
]
)
\max\left(f\left[l,l+2^s -1\right],f\left[r-2^s + 1, r\right]\right)
max(f[l,l+2s−1],f[r−2s+1,r])来找到
[
l
,
r
]
\left[l,r\right]
[l,r]的最大值
(为什么不是
[
l
+
2
s
,
r
]
\left[l +2^s,r\right]
[l+2s,r]?因为有可能越界)
剩下的就是可以考虑预处理 log 2 \log_2 log2
int logn[N] = { -1, 0 };//floor( log2 n )
//预处理log2
for (int i = 2; i <= n; ++i) {
logn[i] = logn[i >> 1] + 1;
}
// pre C++20
int log2_floor(unsigned long long i) {
return i ? __builtin_clzll(1) - __builtin_clzll(i) : -1;
}
// C++20
#include <bit>
int log2_floor(unsigned long i) {
return std::bit_width(i) - 1;
}
洛谷P3865
#include<cstdio>
#include<algorithm>
const int N = 1e5 + 5;
int logn[N] = { -1, 0 };//floor( log2 n )
int st[N][21];
int main() {
int n, m;
scanf("%d%d", &n, &m);
//预处理log2
for (int i = 2; i <= n; ++i) {
logn[i] = logn[i >> 1] + 1;
}
for (int i = 1; i <= n; ++i) {
scanf("%d", &st[i][0]);
}
//预处理
for (int j = 1; j <= logn[n]; ++j) {
for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
st[i][j] = std::max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
}
while (m--) {
int l, r;
scanf("%d%d", &l, &r);
int s = logn[r - l + 1];
printf("%d\n", std::max(st[l][s], st[r - (1 << s) + 1][s]));
}
return 0;
}