洛谷 P3865 【模板】ST表

洛谷 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;
}
上一篇:武大2020-2021年校历


下一篇:21.2.3总结