• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

RomanLin

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

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

题目

https://www.luogu.com.cn/problem/P3865

题解

ST表(Sparse Table,稀疏表)主要用来解决 RMQ(区间最大/最小值查询)问题。主要应用倍增思想,可以实现 \(O(nlogn)\) 预处理,\(O(1)\) 查询。

凡是符合结合律和可重复贡献的信息查询都可以使用 ST 表进行维护,比如最大值、最小值、最大公因数、最小公倍数、按位与和按位或等。

值得注意的是,ST 表更适合于静态查询的情景,若涉及动态查询,则需要重新建立 ST 表,否则答案可能错误,动态查询更推荐使用线段树。

预处理 ST 表
倍增法递推:用两个等长小区间拼凑一个大区间。

定义 \(dp[i][j]\) 为以第 \(i\) 个数为起点,长度为 \(2^j\) 的区间中的最大(小)值。当枚举的区间长度为 \(2^j\) 时,区间为 \([i, i+2^j-1]\),即区间终点为 \(i + (1<<j)-1\)。
image

得到动态转移方程:$$dp[i][j] = max(dp[i][j - 1], dp[i + 2^{j-1}][j - 1])$$

处理查询
对查询区间 \([l,r]\) 做分割、拼凑,区间长度的指数为 \(k=log_2(r-l+1)\),易知 \(2^k \leq r-l+1 \leq 2 \times 2^k\),即 \((r-l+1)\) 可以用两个具有交集的 \(2^k\) 拼凑得到:
image

得到询问的方程:$$res=max(dp[l][k], dp[r-2^k+1][k])$$

本文参考董晓算法所作,若有侵权,可联系修改或删除。

参考代码

#include<iostream>
#include<vector>
#include<cmath>
#include<functional>

template<typename T, typename E, typename F>
class SparseTable {/*稀疏表*/
private:
    std::vector<std::vector<E>> dp;
    F func;
public:
    SparseTable(T& arr, int arr_size, F func): func(func) {
        int log2_arr_size = log2(arr_size) + 1;
        dp.assign(arr_size, std::vector<E>(log2_arr_size));
        for (int i = 0; i < arr_size; ++ i) dp[i][0] = arr[i];// 初始化第一层
        for (int j = 1; j < log2_arr_size; ++ j) {// 枚举区间长度 2^j
            int step = 1 << j;// 区间长度
            for (int i = 0; i + step - 1 < arr_size; ++ i) {// 枚举区间起点
                dp[i][j] = func(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
            }
        }
    }

    E query(int l, int r) {// 下标从 0 开始
        int k = log2(r - l + 1);
        return func(dp[l][k], dp[r - (1 << k) + 1][k]);
    }
};

inline int read() {
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
    return x*f;
}

int Max(int a, int b) {
    return a > b ? a : b;
}

int main() {
    std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout.tie(nullptr);
    int n, m, l, r;
    n = read(), m = read();
    std::vector<int> v(n);
    for (int i = 0; i < n; ++ i) v[i] = read();
    SparseTable<std::vector<int>, int, std::function<int(int, int)>> st(v, n, Max);
    // SparseTable<std::vector<int>, int, decltype(&Max)> st(v, n, Max);
    while (m --) {
        l = read(), r = read();
        -- l, -- r;
        std::cout << st.query(l, r) << '\n';
    }
    return 0;
}

posted on 2026-01-18 22:27  RomanLin  阅读(10)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3