TYS的博客

算法小白努力学习中

0%

ST表

题目

https://www.luogu.com.cn/problem/P3865

给定一个长度为N的数列和M次询问,求出每一次询问的区间内数字最大值。

st

f[i][j]表示区间$[i, i + 2^j - 1]$的最大值。根据倍增的思想,可以写出状态转移方程$f[i][j] = max(f[i][j - 1], f[i + 2^{j - 1}][j - 1])$

因此对于每个询问[l, r],我们将其分为两部分$[l, l + 2^s - 1], [r - 2^s + 1, r]$,其中$s = log_2(r - l + 1)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<bits/stdc++.h>
using namespace std;
static constexpr int MAXN = 1e5 + 5;
int f[MAXN][21];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
int n, m, l, r, s;
cin >> n >> m;
vector<int> arr(n, 0);
for (int i = 0; i < n; i++) {
cin >> arr[i];
f[i][0] = arr[i];
}
for (int j = 1; j <= 20; j++) {
for (int i = 0; i + (1 << (j - 1)) < n; i++) {
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
}
for (int i = 0; i < m; i++) {
cin >> l >> r;
s = log2(r - l + 1);
cout << max(f[l][s], f[r - (1 << s) + 1][s]) << endl;
}
return 0;
}