ST 表学习笔记

ST表

ST表,这是一个好东西。可以用来查询区间最值,但是不可以进行修改。

它可以做到 O(nlog(n))O(n\log(n)) 预处理,O(1)O(1) 查询。

前置知识:倍增,dpdp

ST 表的优点就在于他可以用倍增来优化预处理的时间。

以模板为例。

【模板】ST 表

dp[i][j]dp[i][j] 表示第 ii 个数,[i,i+2j1][i,i+2^j-1] 内的最大值。

考虑转移,对于当前的区间最大值,可以由两个小区间组合而成。

比如,如图中 dp[1][2]dp[1][2] 即可由 max(dp[1][1],dp[3][1])max(dp[1][1],dp[3][1]) 转移得到。 ( [1,4][1,4][1,2][1,2][3,4][3,4] 合成)。

所以,转移的时候我们可以写成:

dp[i][j]=max(dp[i][j1],dp[i+2j1][j1])dp[i][j]=max(dp[i][j-1],dp[i+2^{j-1}][j-1])

然后,这就是类似一个区间 dpdp 的过程,然后要考虑边界:

假设当前区间长度为 1212i=6i=6j=3j=3 的时候,表示的区间是 [6,6+8][6,6+8],就不正确了。实际上,在 j=3j=3 的时候,ii 只可以取到 [1,5(1223+1)][1,5(12-2^3+1)]

所以不难得出,ii 的边界在 [1,122j+1][1,12-2^j+1] 中。

关于求 jj,我们知道 2jn2^j\leq njlog(n)j\leq \log(n),用 log2\log2 函数即可。

以上部分是预处理,时间复杂度 O(nlog(n))O(n\log(n))

现在就到了求最值。

假设我们需要求 [l,r][l,r] 的最值,就是把两个 ST 表可以直接维护的小区间,合并成这个区间的最大值。

对于起始点,我们找一个ST 表内可以覆盖的最大区间,即 log(rl+1)\log(r-l+1),记为 kk ,这一段就是 dp[l][k]dp[l][k]

由于 dp[l][k]dp[l][k] 不一定可以覆盖完整个区间,我们还需要一个 dp[r2k+1][k]dp[r-2^k+1][k],( kk 可以覆盖的区间是 [L,L+2k1][L,L+2^k-1],大小是 2k2^k,所以就会剩下 r2kr-2^k 的数未被覆盖。而 dp[r2k+1][k]dp[r-2^k+1][k] 正好可以覆盖这部分的数)。

所以就可以 O(1)O(1) 的求了。

ans=max(dp[l][k],dp[r2k+1][k]ans=max(dp[l][k],dp[r-2^k+1][k]

其中,2i2^i 可以写成 (1<<i)(1<<i) 加快速度。

CodeCode

P2880 [USACO07JAN] Balanced Lineup G

练手题,维护当前区间的最大值和最小值即可。

CodeCode

P4392[BOI2007]Sound 静音问题

SP7739 BOI7SOU - Sound

做法和上面略同,不再赘述,可以练手。

当然,各位要注意的是,ST 表 只是一个数据结构,对于一个静态区间的题目而言,他只是一个工具,对一道题而言,只有想到怎么样转换,才是有意义的。

CF1548B

ST表+二分解决静态区间GCD 问题。

首先看到同余,转成求 gcd\gcd 的方法就是,差分。

根据余数的可减性,可以知道,求出 gcd\gcd 即可,即可同余。

这就转换成了求一个 gcd\gcd 不为 11 的最大区间。

通过二分求即可。

CodeCode

ST 表+欧拉序求LCA:

欧拉序,简而言之就是树的深搜,回溯的结点也需要标记。

拿最开始的图来说,他的欧拉序就是:1,3,5,3,6,3,1,4,1 1,3,5,3,6,3,1,4,1

对于我们要找的两个点的LCA,就是他们两个点(如果一个点出现多次,任取一个)之间的深度最小值。

由于每个节点的深度是静态的,所以我们可以使用 ST 表维护。注意,维护的是区间内最小值的点的编号。

不会的同学可以左转:ST表学习笔记

CodeCode

posted @   June_Failure  阅读(9)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示