ST表

模板题:https://www.luogu.com.cn/problem/P3865

要注意的几个点就是ST表是用来求解可重复贡献问题的,也就是一个值可以被用来计算两次而不影响结果,也就是区间可以重叠。其他的看代码注释。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
//#define fre
//#define DEBUG
using namespace std;
const int maxn = 100005, logm = 18; // logm后面在预处理的时候会用到
int f[maxn][logm], logto[maxn];
void pre() // 预处理log2的值
{
    logto[1] = 0, logto[2] = 1;
    for (int i = 3; i < maxn; ++i)
    {
        logto[i] = logto[i >> 1] + 1;  // 用换底公式可以推出,但我一开始没想明白如果i是奇数会不会出错,因为此时log[i]=log[i-1]
                                       // 但实际上log[i-1]<=log[i],如果是错的话那么只能log[i-1]=log[i]-1,产生这种情况只可能
                                       // 是i在2的n次方的分界点,又因i是奇数,假设i=2^n+1,log[i-1]=n=log[i]仍然成立。
    }
}
int main()
{
    #ifdef fre
    freopen("in.in", "r", stdin);
    freopen("out.txt", "w", stdout);
    #endif
    int n, m, l, r;
    pre();
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; ++i) scanf("%d", &f[i][0]);
    // 注意这里的循环顺序
    for (int j = 1; j < logm; ++j)
    {
        for (int i = 0; i + (1 << j) - 1 < n; ++i) // 注意这里的范围控制,保证当前更新的区间的右端点小于n
        {
            f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
        }
    }
    for (int i = 0; i < m; ++i)
    {
        scanf("%d%d", &l, &r);
        --l, --r;
        int t = logto[r - l + 1];
        printf("%d\n", max(f[l][t], f[r - (1 << t) + 1][t]));
    }   
}
posted @ 2020-03-27 11:10  JonKitten  阅读(113)  评论(0)    收藏  举报