学习笔记:ST 表
ST 表
ST 表是用于解决 可重复贡献问题 的数据结构。
ST 表可以做到 预处理, 回答每个询问。但不支持修改操作。
基于倍增思想,我们考虑如何求出区间最大值。可以发现,如果按照一般的倍增流程,每次跳 步的话,询问时的复杂度仍旧是 ,并没有比线段树更优,反而预处理一步还比线段树慢。
然而,我们发现显然有 ,也就是说,区间最大值是一个具有「可重复贡献」性质的问题。即使用来求解的预处理区间有重叠部分,只要这些区间的并是所求的区间,最终计算出的答案就是正确的。
如果手动模拟一下,可以发现我们能使用至多两个预处理过的区间来覆盖询问区间,也就是说询问时的时间复杂度可以被降至 ,在处理有大量询问的题目时十分有效。
具体实现如下:
令 表示区间 的最大值。
显然有 。
根据定义式,第二维就相当于倍增的时候「跳了 步」,依据倍增的思路,写出状态转移方程:
以上就是预处理部分。而对于查询,可以简单实现如下:
对于每个询问 ,我们把它分成两部分: 与 ,其中 两部分的结果的最大值就是回答。
根据上面对于「可重复贡献问题」的论证,由于最大值是「可重复贡献问题」,重叠并不会对区间最大值产生影响。又因为这两个区间完全覆盖了 ,可以保证答案的正确性。
#include <iostream>
#define MAXN 100005
using namespace std;
int n, m, x, y, op;
int lg[MAXN];
int st[MAXN][25];
int read(){
int t = 1, x = 0;char ch = getchar();
while(!isdigit(ch)){if(ch == '-')t = -1;ch = getchar();}
while(isdigit(ch)){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * t;
}
void write(int x){
if(x < 0){putchar('-');x = -x;}
if(x >= 10)write(x / 10);
putchar(x % 10 + '0');
}
int main(){
n = read();m = read();
for(int i = 1 ; i <= n ; i ++)st[i][0] = read();
for(int i = 2 ; i <= n ; i ++)lg[i] = lg[i >> 1] + 1;
for(int i = 1 ; i <= lg[n] ; i ++)
for(int j = 1 ; j <= n - (1 << i) + 1 ; j ++)
st[j][i] = max(st[j][i - 1], st[j + (1 << (i - 1))][i - 1]);
for(int i = 1 ; i <= m ; i ++){
x = read();y = read();op = lg[y - x + 1];
write(max(st[x][op], st[y - (1 << op) + 1][op]));putchar('\n');
}
return 0;
}
注意
- 输入输出数据一般很多,建议开启输入输出优化。
-
每次重新计算 函数值并不值得,建议进行如下的预处理:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】