ST表
ST表
核心:倍增,DP
ST表的核心思想就是倍增和DP的结合,能够用 \(n\log n\) 的时间和空间复杂度的预处理换来 \(O(1)\) 的查询
当题目不涉及带修的时候求最值,ST表必定是最好的选择
我们设 \(f_{i,j}\) 表示从第 \(i\) 个数开始往后数 \(2^j\) 个数的最大值,即表示 \([i,i+2^j-1]\) 这段区间的最大值
首先,当 \(j=0\) 时即表示 \([i,i]\) 也就是 \(a_i\) 的值
我们可以先枚举 \(j\),然后枚举 \(i\),转移方程可以写成
此时我们考虑一下上面的式子的正确性
\(f_{i,j-1}\) 表示 \([i,i+2^{j-1}-1]\)这段区间的最大值
\(f_{i+2^{j-1},j-1}\) 表示 \([i+2^{j-1},i+2^{j-1}+2^{j-1}]\) 即 \([i+2^{j-1},i + 2^j]\) 这一段的最大值
两个拼起来正好和 \(f_{i,j}\) 的意义一致
那么我们怎么查询呢?
我们考虑,首先预处理出 \(lg\) 数组
对于每次读入的 \(l,r\),我们首先找到 \(k=lg_{r-l+1}\)
我们的答案即为 \(\max(f_{l,k},f_{r-2^k+1,k})\)
接下来我们证明这个答案的正确性
\(f_{l,k}\) 表示 \([l,l + 2^k-1]\)
\(f_{r-2^k+1,k}\) 表示 \([r-2^k+1,r]\)
我们现在要证明两个集合的并集为 \([l,r]\)
我们会发现
只需证 \(l+2^k-1+1 \ge r-2^k+1\)
注意上面我们的 \(l+2^k-1\) 要加一
这个很显然了,因为 \(lg_{r-l+1} = k\)
所以 \(2^{k+1}\) 必然大于 \(r-l+1\),不然的话,若 \(2^{k+1}\ge r-l+1\),则 \(log_{r-l+1}> k\)
得证,我们证得上面的式子并集恰好为 \([l,r]\)
code
int n, m;
int a[N], st[N][21], lg[N];
int main() {
read(n, m);
rep(i, 1, n) read(st[i][0]);
rep(i, 2, n) lg[i] = lg[i >> 1] + 1;
rep(j, 1, 20)
rep(i, 0, n + 1 - (1 << j))
st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
rep(i, 1, m) {
int x, y, k;
read(x, y);
k = lg[y - x + 1];
write(max(st[x][k], st[y - (1 << k) + 1][k]), '\n');
}
return 0;
}
// write:RevolutionBP