• ST表--适用多查询O(1)


    ST表类似树状数组,线段树这两种算法,是一种用于解决RMQ问题的离线算法。

    预处理(O(nlogn)),查询(O(1))

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

    定义:

    (st[i][j])表示从(i)位置开始的(2^j)个数中的最大值,即(st[i][j] = max(a_i,...a_{i + 2^j-1}))

    预处理

    (O(nlogn))

    img

    (st[i][j])对应的([i,i + 2^j - 1])分成([i,i + 2^{j - 1} - 1])([i+2^{j - 1},i+2^j-1])两部分

    对应的是(st[i][j - 1])(st[i + (1 << j) - 1][j - 1])

    [st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); ]

    查询

    (O(1))

    img

    ([l,r])分成两个有交集的区间([l,l + 2^k-1])([r - 2^k + 1][r])

    [k = log2(r - l + 1)\ ans = max(st[l][k],st[r - (1 << k) + 1][k]) ]

    打表观察

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    const int N = 3e5 + 5;
    int st[N][22];
    int main(){
        int n = 20;
        for(int j = 1; j <= 20; j++)
            for(int i = 1; i + (1 << j) - 1 <= n; i++)
                printf("%d [%d,%d] [%d,%d]
    ", 1 << (j - 1), i, i + (1 << (j - 1)) - 1, i + (1 << (j - 1)), i + (1 << j) - 1);
        return 0;
    }
    

    {{uploading-image-762726.png(uploading...)}}

    可以观察其变化情况

    模板

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    const int N = 1e5 + 5;
    int st[N][20];
    int query(int l, int r){
        int k = log2(r - l + 1);
        return max(st[l][k], st[r - (1 << k) + 1][k]);
    }
    int main(){
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)
            scanf("%d", &st[i][0]);
        
      int k = log2(n / 2) + 1; //常数优化
        for(int j = 1; j <= 17; j++) // j in [1, k]
            for(int i = 1; i +(1 << j) - 1 <= N; i++)
                st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
        for(int i = 1; i <= m; i++){
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%d
    ", query(l, r));
        }
        return 0;
    }
    

    扩展

    st表必定是一个单调函数

    • 维护最大值的st表 - 单调递增
    • 维护最小值的st表 - 单调递减

    可以用二分去寻找满足条件的区间个数

    遍历下左区间,然后二分在st表里查找右区间

    同时,st表也可以去维护其他的,比如区间LCA

    总之,对于区间RMQ问题,或者区间问题,多组查询,且不修改,ST表很好用

  • 相关阅读:
    qemu-kvm磁盘读写的缓冲(cache)的五种模式
    关于追踪qemu 源码函数路径的一个方法
    准备升大三啦
    关于Vim的一个配置文件
    POJ 3253
    hihocoder 第二十五周 spfa 最短路
    POJ 2718 穷举
    《鸟哥Linux私房菜基础学习篇》命令索引
    博文流
    《SDN核心技术剖析和实战指南》3.3读书笔记
  • 原文地址:https://www.cnblogs.com/Emcikem/p/11561412.html
Copyright © 2020-2023  润新知