前言

学习ST表,主要是倍增思想,可以理解为倍增优化后的DP。写在这里,一方面方便自己以后复习,另一方面给其他人参考。

UPD on 2023/3/21 :修改了格式,使格式与其他的学习笔记统一。

倍增

倍增引入

与其说倍增是一种算法,不如说倍增是一种思想。

倍增的时间复杂度和二分是一样的,都是 \(O(\log n)\) 。唯一的区别是倍增与二分的方向是相反的。倍增思想常用来优化算法的时空复杂度( \(O(n)\to O(\log n)\) ),和其他算法搭配使用。

我们进行递推时,如果状态空间很大,通常线性递推无法满足时空复杂度的要求,那可以通过成倍增加,以 \(2\) 的整数次幂为代表。如 \(13\),可以表示为

\[13=2^3+2^2+2^0
\]

对于 \(2\) 的 \(n\) 次幂,可以通过位运算快速求出。

i=(1<<(n-1))

注意:由于位运算优先级分布不均匀,使用时一般搭配括号

倍增的经典应用:快速幂,ST表,LCA,后缀数组。

ST表

ST表可以用来解决RMQ(区间最值询问)问题,是一个离线算法。这里求解的是区间最小值问题。当询问数量较多,达到 \(10^6\) 甚至更多且没有修改操作时,考虑使用ST表

主要思想

预处理

设状态 \(dp[i][j]\) 表示区间 \([i,i+2^j-1]\) 的最小值。

易得 \(dp[i][0]=a[i]\)

状态转移方程如下:

\[dp[i][j]=\min\{dp[i][j-1],dp[i+2^{j-1}][j-1]\}
\]

由状态定义得,其中 \(dp[i][j-1]\) 表示区间 \([i,i+2^{j-1}-1]\) 的最小值, \(dp[i+2^{j-1}][j-1]\) 表示下面区间的最小值:

\[[i+2^{j-1},i+2^{j-1}+2^{j-1}-1]=[i+2^{j-1},i+2^j-1]
\]

由于相交或相接的区间可以合并,故把 \(dp[i][j]\) 分为两段,分别求出最小值,再取最小值合并。

注意:由于 \(dp[i][j]\) 是由 \(dp[i][j-1]\) 和 \(dp[i+2^{j-1}][j-1]\) 转移来的,所以对于变量 \(j\) 的循环要在外层

预处理完整代码如下:

for(int i=1;i<=n;i++)
f[i][0]=a[i];
for(int j=1;j<=MAXM;j++)
for(int i=1;i+(1<<(j-1))<=n;i++)
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);

时间复杂度:\(O(n\log n)\)

询问

对于询问区间 \([s,t]\) ,首先取

\[k=(int)log2(t-s+1)
\]

然后可得

\[RMQ[s,t]=\min\{dp[s][k],dp[t-2^k+1][k]\}
\]

由状态定义得,其中 \(dp[s][k]\) 表示区间 \([s,s+2^k-1]\) 的最小值, \(dp[t-2^k+1][k]\) 表示下面区间的最小值:

\[[t-2^k+1,t-2^k+1+2^k-1]=[t-2^k+1,t]
\]

很显然,这两个区间是相交或相接的,故可以合并最小值,求出答案。

回答询问完整代码如下:

int k=(int)log2(t-s+1);
printf("%d\n",max(f[s][k],f[t-(1<<k)+1][k]));

时间复杂度:\(O(1)\)

ST表例题

例题 \(1\) :

P3865 【模板】ST 表

ST表模板题,不多赘述。

#include <bits/stdc++.h>
#define MAX 600000
using namespace std;
int n,m,s,t,a[2000000],f[100050][21];
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 main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=n;i++)
f[i][0]=a[i];
for(int j=1;j<=20;j++)
for(int i=1;i+(1<<(j-1))<=n;i++)
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
for(int i=1;i<=m;i++)
{
s=read();t=read();
int k=(int)log2(t-s+1);
printf("%d\n",max(f[s][k],f[t-(1<<k)+1][k]));
}
return 0;
}

例题 \(2\) :

P2880 [USACO07JAN] Balanced Lineup G

很显然,只需要改变 \(\min\) 和 \(\max\) ,就可以从求最小值转化为求最大值。

\[dp[i][j]=\max\{dp[i][j-1],dp[i+2^{j-1}][j-1]\}
\]
\[k=(int)log2(t-s+1)
\]
\[RMQ[s,t]=\max\{dp[s][k],dp[t-2^k+1][k]\}
\]
#include <bits/stdc++.h>
using namespace std;
int n,m,s,t,a[2000000],f[100050][21],f2[100050][21];
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 main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=n;i++)
f[i][0]=a[i],f2[i][0]=a[i];
for(int j=1;j<=20;j++)
for(int i=1;i+(1<<(j-1))<=n;i++)
{
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
f2[i][j]=min(f2[i][j-1],f2[i+(1<<(j-1))][j-1]);
}
for(int i=1;i<=m;i++)
{
s=read();t=read();
int k=(int)log2(t-s+1);
printf("%d\n",max(f[s][k],f[t-(1<<k)+1][k])-min(f2[s][k],f2[t-(1<<k)+1][k]));
}
return 0;
}

后记

RMQ问题还可以用线段树来解决,这里不多赘述。

教练推荐的一篇博客:

倍增与ST算法 --算法竞赛专题解析(28)

【6】ST表学习笔记的更多相关文章

  1. ST表学习笔记

    ST表是一种利用DP思想求解最值的倍增算法 ST表常用于解决RMQ问题,即求解区间最值问题 接下来以求最大值为例分步讲解一下ST表的建立过程: 1.定义 f[i][j]表示[i,i+2j-1]这个长度 ...

  2. S-T表学习笔记

    $O(nlogn)$构造$O(1)$查询真是太强辣 然而不支持修改= = ShØut! #include<iostream> #include<cstring> #includ ...

  3. Servlet乘法表学习笔记

    一.控制台实现乘法表 package com.shanrengo; import java.io.IOException; import java.io.PrintWriter; import jav ...

  4. ST表学习总结

    前段时间做16年多校联合赛的Contest 1的D题(HDU 5726)时候遇到了多次查询指定区间的gcd值的问题,疑惑于用什么样的方式进行处理,最后上网查到了ST表,开始弄得晕头转向,后来才慢慢找到 ...

  5. st表复习笔记

    st表,一种高效的区间最值查询(RMQ)算法.本质其实是一个动态规划. 其实吧,对于看过线性dp的人来说应该不难理解,只是处理有些麻烦.但是本土狗因为-1的问题居然改了许久... 用两个2^i的区间把 ...

  6. ST 表练习笔记

    P2048 [NOI2010]超级钢琴 首先按照 前缀和最大值 建立 \(ST\) 表 对于每一个 \(i\) 维护一个以他为起始点的最大的 "超级和弦" (\(ST\) 表 \( ...

  7. java线性表学习笔记(一)

    线性表是一种按顺序储存数据是的常用结构,大多数的线性表都支持以下的典型操作: 从线性表提取插入删除一个数据: 找出线性表中的某一个元素: 找出线性表中的元素: 确定线性表中是否包含某一个元素,确定线性 ...

  8. ST表学习

    啊谈不上学习了.复习一下原理留一下板子. $f\left[i,j \right]$表示以$i$为起点,区间长度为${2}^{j}$的区间最值.以最小值为例,即 $min\left(a\left [ k ...

  9. windows注册表学习笔记

    注册表,想起来了就学学,方便操作.无需把它当成重要学问,今日就学一波,作为了解. 一.注册表清理脚本 主要是删除临时文件,旧文件.并不能够删除无效的键 @echo off del/f/s/q %sys ...

  10. ST 表学习

    作用:ST算法是用来求解给定区间RMQ的最值,本文以最小值为例 举例: 给出一数组A[0~5] = {5,4,6,10,1,12},则区间[2,5]之间的最值为1. 方法:ST算法分成两部分:离线预处 ...

随机推荐

  1. Springboot连接Greenplum,分页查询

    1.springboot分页查询greenplum数据报错: org.mybatis.spring.MyBatisSystemException: nested exception is org.ap ...

  2. Rocketmq 如何保证消息的可用性/可靠性/不丢失呢 ?

    如何保证消息的可用性/可靠性/不丢失呢 ? 消息可能在哪些阶段丢失呢?可能会在这三个阶段发生丢失:生产阶段.存储阶段.消费阶段 生产阶段 在生产阶段,主要通过请求确认机制,来保证消息的可靠传递 1.同 ...

  3. H5 ios端微信浏览器下-底部工具固定方法

    在外层配置css position: fixed; width: 100%; top: 0px; bottom: 0px; overflow: auto; 结束

  4. eolinker请求参数:提交参数JSON转换格式不正确的解决方法

    当某个接口的提交参数类型为"array"时,该接口被自动化测试调用会转换成text类型. 导致执行测试的时候,整个参数转化json格式不正确 解决方法是在  格式不正确的项后面 配 ...

  5. 智能语音备忘录:SpeechRecognition与gTTS的奇妙融合

    引言:智能语音备忘录的时代已经到来 在这个信息爆炸的时代,我们每天需要处理大量的事务和信息.传统的文字记录方式虽然可靠,但在效率上往往难以满足快节奏生活的需求.想象一下,如果你能在驾车.散步或是灵感突 ...

  6. 特殊符号大全,特殊字符、emoji符号收藏,可复制直接使用

    收藏包含:特殊符号.emoji符号.编号序号.数学符号.上标下标.标点符号.货币符号.箭头符号.国旗符号等 ❥웃유☮☏☢☠♚▲♪✞÷↑↓◆◇⊙■□△▽¿─│❣♂♀☿Ⓐ✍☣☤✘☒♛▼♫⌘☪≈←→◈◎☉★ ...

  7. Nim 语言新的性能测试

    今天将 性能测试网站: benchmarks game 上一个关于 n-body 的题目改成 nim 1.6.4 语言来编写. 注意,我是基于 java 的版本来写的,没有像  c++ 那样的版本使用 ...

  8. df -h命令卡住 怎么办

    df -h命令卡住 命令行输入df -h却发现一直卡在那里,有可能是挂载出了问题. 这种问题,大概率是由于 mount 的目录被删除了,但是没有提前执行 umount 操作,因此报错! 解决方法: 1 ...

  9. 时间工具类之“LocalDateTime方案转换地域性时差问题->UTC时间转纽约时间”

    一.使用方法 1.获取纽约ZoneId[纽约时区的ZoneId标识为"America/New_York"] -> ZoneId.of("America/New_Yo ...

  10. IDEA问题之“接口路径查询插件【RestfulToolkit】”

    一.场景 只查询Java代码中的路径,这样就可以快速的找到对应的接口 快捷键:Ctrl + \ 二.安装步骤