跳转至

ST表

2025-05-30

ST表(Sparse Table, 稀疏表) 可以实现 O(1) 查询区间 RMQ,线段树和树状数组查询 RMQ 是 O(\(\log n\)) 的,但 ST 表是不支持修改的。

ST表是基于倍增思想,倍增也可以解决其他的问题,代码都跟 ST 表差不多,感觉非常神奇。

之前老是不太记得ST表怎么写,一般要用时会翻书看,用的次数也不是很多,但其实稍微理解下,就很容易记住了。

P3865 【模板】ST 表 && RMQ 问题

才黄色难度。。。虽然确实一下就能学会。

数组会比 vector 快一些。

#include<bits/stdc++.h>
using namespace std;

struct ST{
    vector<int> LOG2;
    vector<vector<int>> info;

    int op(int x, int y){
        return max(x, y);
    }
    ST(vector<int> &vec){
        // 1-index 
        int n = vec.size() - 1;
        LOG2.assign(n + 1, 0);
        // LOG2[1] = 0;
        for(int i = 2; i <= n; i++)
            LOG2[i] = LOG2[i >> 1] + 1;
        info.assign(n + 1, vector<int> (LOG2[n] + 1, 0));
        for(int i = 1; i <= n; i++){
            info[i][0] = vec[i];
        }
        for(int k = 1; k <= LOG2[n]; k++){
            for(int i = 1; i + (1 << k) <= n + 1; i++){
                info[i][k] = op(info[i][k - 1], info[i + (1 << (k - 1))][k - 1]);
            }
        }
    }
    int query(int l, int r){
        int k = LOG2[r - l + 1];
        return op(info[l][k], info[r - (1 << k) + 1][k]);
    }
};

int main()
{
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int n, q;
    cin >> n >> q;
    vector<int> a(n + 1);
    for(int i = 1; i <= n; i++)
        cin >> a[i];
    ST st(a);
    while(q--){
        int l, r;
        cin >> l >> r;
        cout << st.query(l, r) << "\n";
    }
    return 0;
}