C++ ST表

最近反正学得很杂,做到什么发现还不会就写写吧。(我也不知道我为什么现在还不会ST表)

初始化就是倍增,以前一直不知道怎么查询,一看博客发现世界真奇妙,原来可以通过两个重合了一部分的区间来查询,,,,,,,,,


f [ i ] [ j ] f[i][j] f[i][j]表示 i i i开始的长度为 2 j 2^j 2j的区间的最大(小)值,先初始化 f [ i ] [ 0 ] = a i f[i][0]=a_i f[i][0]=ai,递推式 f [ i ] [ j ] = max ⁡ {   f [ i + 2 j − 1 ] [ j − 1 ] , f [ i ] [ j − 1 ]   } f[i][j]=\max\{\ f[i+2^{j-1}][j-1],f[i][j-1]\ \} f[i][j]=max{ f[i+2j1][j1],f[i][j1] },这个和倍增求LCA差不多。

要求 [ l , r ] [l,r] [l,r]的最大值,可以这样:
求最值图示
k = ⌊ log ⁡ 2 ( r − l + 1 ) ⌋ k=\left\lfloor\log_2\left(r-l+1\right)\right\rfloor k=log2(rl+1),则 [ l , r ] [l,r] [l,r]的最大值是 max ⁡ {   f [ l ] [ k ] , f [ r − 2 k + 1 ] [ k ]   } \max\{\ f[l][k],f[r-2^k+1][k]\ \} max{ f[l][k],f[r2k+1][k] }
但是我也不知道为什么求 ⌊ log ⁡ 2 ( r − l + 1 ) ⌋ \left\lfloor\log_2\left(r-l+1\right)\right\rfloor log2(rl+1) 2 k 2^k 2k1<<k)是 O ( 1 ) O(1) O(1)的(难道不是 O ( log ⁡ ) O(\log) O(log)的吗)。


log ⁡ \log log存下来可以优化一些。

<think>好的,用户想了解C++ST的实现与用法。首先,我需要回忆ST的基本概念和原理。ST,也就是稀疏,主要用于处理静态数组的区间最值查询问题。它的核心思想是预处理和动态规划,通过构建一个二维数组来存储不同区间的预处理结果,从而在查询时以O(1)的时间复杂度得到结果。 接下来,我应该整理ST的实现步骤。首先,预处理阶段需要确定log2,方便快速计算区间长度对应的指数。然后,构建ST的结构,使用动态规划的方法填充每个起点和区间长度的最大值或最小值。这里要注意的是,ST适用于静态数据,一旦数据变动,就需要重新构建,所以应用场景通常是数据不变的情况。 然后,考虑用户可能的疑问点。例如,ST的构建时间复杂度是O(n log n),而查询是O(1),这比线段树的O(n)构建和O(log n)查询更有优势,但ST不支持动态更新。用户可能想知道如何在实际应用中选择合适的数据结构,比如静态场景下ST更高效,动态则需要线段树或树状数组。 接下来,我需要参考提供的引用内容。引用[2]提到稀疏用于静态数组,预处理时间O(n logn),查询O(1)。引用[3]和[4]提供了C++实现的模板,其中提到可以修改查询操作为最大值或其他操作。因此,在代码示例中,应该展示如何根据需求调整最大值或最小值,并解释代码中的关键部分,比如log_table的初始化、ST的构建和查询方法。 用户可能还会关心ST的应用场景,比如在RMQ(区间最值查询)问题中的使用,如LeetCode上的题目或竞赛编程中的常见问题。需要举例说明,比如滑动窗口中的最大值或者需要频繁查询静态数组区间最值的场景。 此外,要注意代码的正确性和可读性。给出的代码示例应该包含构造函数处理输入数组,预处理log_table,填充st,以及查询函数的实现。同时,要指出代码中可能需要注意的地方,比如数组索引从1开始还是0开始,这会影响log_table的计算和区间划分。 最后,生成相关问题时要覆盖ST的优化、与其他数据结构的比较、应用实例以及可能的时间复杂度分析。这些问题可以帮助用户进一步深入理解ST的相关知识。</think>### C++ ST实现与用法详解 #### 一、ST基础概念 ST(Sparse Table)是用于**静态数组区间最值查询**(Range Minimum/Maximum Query, RMQ)的高效数据结构。其核心特点是通过$O(n \log n)$的预处理时间,实现$O(1)$时间复杂度的查询[^2]。 #### 二、实现步骤 1. **预处理log** ```cpp vector<int> log_table; void init_log(int n) { log_table.resize(n + 1); for (int i = 2; i <= n; ++i) log_table[i] = log_table[i/2] + 1; } ``` 2. **构建ST** ```cpp vector<vector<int>> st; void build(const vector<int>& arr) { int n = arr.size(); int k = log2(n); st.resize(n, vector<int>(k+1)); for (int i = 0; i < n; ++i) st[i][0] = arr[i]; for (int j = 1; j <= k; ++j) for (int i = 0; i + (1<<j) <= n; ++i) st[i][j] = max(st[i][j-1], st[i + (1<<(j-1))][j-1]); } ``` 3. **区间查询** ```cpp int query(int l, int r) { int len = r - l + 1; int k = log_table[len]; return max(st[l][k], st[r - (1<<k) + 1][k]); } ``` #### 三、关键特性 1. **适用场景**:静态数据集的多次查询(如基因序列分析、地理信息系统中地形高程查询) 2. **时间复杂度**: - 预处理:$O(n \log n)$ - 查询:$O(1)$ 3. **空间复杂度**:$O(n \log n)$ #### 四、应用示例 ```cpp int main() { vector<int> data = {3, 1, 4, 5, 2, 9}; init_log(data.size()); build(data); cout << query(0, 2) << endl; // 输出4(区间[0,2]最大值) cout << query(3, 5) << endl; // 输出9 } ``` #### 五、与同类结构对比 | 数据结构 | 预处理时间 | 查询时间 | 动态更新 | |----------|------------|----------|----------| | ST | $O(n \log n)$ | $O(1)$ | ❌ | | 线段树 | $O(n)$ | $O(\log n)$ | ✔️ | | 树状数组 | $O(n)$ | $O(\log n)$ | ✔️ |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值