ST表模板(求区间最值问题)

ST表的介绍

st表是一种\(O(nlogn)\)预处理,\(O(1)\)查询的数据结构,常用来处理静态数组的区间最值,区间gcd等问题。
st表用到的核心思想是倍增

ST表的原理

定义st[i][j]表示从下标 \(i\) 开始到下标 \(i+2^j\) 这段区间的答案。\((i \leqslant n,\quad 2^j \leqslant n)\)
预处理代码:

for(int i = 1;i <= n; i++) Max[i][0] = a[i];
    lg2[1] = 0;
for (int i = 2; i <= n; ++i) lg2[i] = lg2[i >> 1] + 1;  //预处理之后会用到的log2函数
for(int j = 1;j <= bi; j++)
    for(int i = 1; i + (1 << j) - 1 <= N; i++)
        Max[i][j] = max(Max[i][j - 1], Max[i + (1 << (j - 1))][j - 1]);

查询:
区间长度\(len\)
首先计算得到一个\(2^k\),保证 \(\frac{len}{2} \leqslant 2^k \leqslant len\)
查询时候分别通过 \(l到l + 2^j\)以及 \(r到r-2^j\)来覆盖整个查询区间。
因为\(max,min,gcd\)等的性质: 单点的重复计算没有贡献

int stQuery(int l,int r){
    int k = lg2[r - l + 1]; 
    return max(Max[l][k], Max[r - (1 << k) + 1][k]);
}

本人的ST表模板:

struct ST{
      int N, bi;  //根据需要传入数组大小和2的幂次
      vector<vector<int>> Max;
      vector<int> lg2;
      ST(int n = 1e5 + 1, int bi = 21): N(n), bi(bi) {
          Max.resize(n + 1, vector<int>(bi + 1, 0));
          lg2.resize(n + 1, 0);
      }
      void stBuild(int n, int a[]){
          for(int i = 1;i <= n; i++) Max[i][0] = a[i];
          lg2[1] = 0;
          for (int i = 2; i <= n; ++i) lg2[i] = lg2[i >> 1] + 1;
          for(int j = 1;j <= bi; j++)
              for(int i = 1; i + (1 << j) - 1 <= N; i++)
                  Max[i][j] = max(Max[i][j-1], Max[i + (1 << (j - 1))][j - 1]);
      }
      int stQuery(int l,int r){
          int k=lg2[r - l + 1]; 
          return max(Max[l][k],Max[r-(1<<k)+1][k]);
      }
};

洛谷模板题:
P3865 【模板】ST 表

int a[N];
struct ST{
    int N, bi;
    vector<vector<int>> Max;
    vector<int> lg2;
    ST(int n = 1, int bi = 1) : N(n), bi(bi) {
        Max.resize(n + 1, vector<int>(bi + 1, 0));
        lg2.resize(n + 1, 0);
    }
    void stBuild(int n, int a[]){
        for(int i = 1;i <= n; i++) Max[i][0] = a[i];
        lg2[1] = 0;
        for (int i = 2; i <= n; ++i) lg2[i] = lg2[i >> 1] + 1;
        for(int j = 1;j <= bi; j++)
            for(int i = 1; i + (1 << j) - 1 <= N; i++)
                Max[i][j] = max(Max[i][j-1], Max[i + (1 << (j - 1))][j - 1]);
    }
    int stQuery(int l,int r){
        int k=lg2[r - l + 1]; 
        return max(Max[l][k],Max[r-(1<<k)+1][k]);
    }
};
void solve(int ce){
    int q;
    cin >> n >> q;
    for(int i = 1; i <= n; i++)cin >> a[i];
    ST st(n,21);
    st.stBuild(n, a);
    while(q--){
        int l, r;
        cin >> l >> r;
        cout << st.stQuery(l, r) << endl;
    }
}   
posted @ 2024-03-22 11:57  SHOJIG  阅读(111)  评论(0)    收藏  举报