洛谷 P3865 【模板】ST表
题目:
题解:
- 把这题丢上来的原因是因为以前学ST的时候是真的水=.=,几乎就是背代码。
- 现在重新看书后有了较深刻的理解:
- 递推时,有公式f(i, j) = max(f(i, j - 1), f(i + \(2^{k+1}\), j - 1)),即长度为\(2^j\)的区间的最大值是左右两半长度为\(2^{j - 1}\)的子区间的max
- 当查询时,先计算出一个k,使得\(2^k\) < r - l + 1 <= \(2^{k + 1}\),那么以l开始的\(2^k\)个数和以r结尾的\(2^k\)个数一定覆盖了整个区间(l, r)。所以取这两子区间的max即可
- 证明很容易,因为两个子区间的长度都为\(2^k\),那么两个子区间的长度和就是\(2^k\) * 2 = \(2^{k+1}\),又\(2^{k+1}\) >= r - l + 1,所以一定覆盖。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define N 100005
using namespace std;
int n, q, logg;
int f[N][31];
int read()
{
int x = 0; char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
return x;
}
int main()
{
memset(f, -0x3f, sizeof(f));
cin >> n >> q;
for(int i = 1; i <= n; i++) f[i][0] = read();
logg = (int)log2(n);
for(int j = 1; j <= logg; j++)
for(int i = 1; i <= n - (1 << j) + 1; i++)
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
for(int i = 1; i <= q; i++)
{
int l = read(), r = read();
logg = (int)log2(r - l + 1);
printf("%d\n", max(f[l][logg], f[r - (1 << logg) + 1][logg]));
}
return 0;
}