ST表
ST表
这个DS自从CSP-2022结束之后,每个星期都要打一次
还是记录一下比较好,写写自己的理解
作用:静态维护区间最大最小值
预处理:O(nlogn)
查询:O(1)
思想就是利用倍增预处理记录端点l开始往后2的幂倍之后对应幂的长度的区间最大值
令2的幂为k,对应区间[l,r]都可以从[l...l+k]和[r-k+1...r]两块区间的最大值转移过来
就像这样
[l.................................r]
MAX
A
[l......l+k] B
[r-k+1....r]
至于正确性,我们考虑从最小的长度2开始,可以直接比出大小,每一个大块都由最初的几个小块组成
大块的最大值或最小值一定是从左右2个小块的最大最小值比较出来的
利用先前算出的小块不断更新大块,即可预处理出ST表
预处理是这样的,然后查询只要确定2的幂次数之后,分同样的两部分区间L与R比较最大值即可
but我们会注意到这样一个问题,预处理时块是不交的
而算的时候有可能是有交的,答案为什么还有正确性呢?
我们考虑把原来这块分成2块A,B ,发现查询时L那块一定包含A,R那块一定包含B
已经包含了初始转移的情况,那整块的最大值从L和R转移过来也是没有问题的
所以正确性可以确保,同时写法也较为简便
最小值的话max换成min即可
上代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int read() {
int x=0,f=1;
char ch=getchar();
while(ch<48||ch>57) {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>=48&&ch<=57) {
x=(x<<3)+(x<<1)+(ch^48);
ch=getchar();
}
return x*f;
}
int anc[N][41],logn[N],n,m;
int querymax(int l,int r) {
int k=logn[r-l+1];
return max(anc[l][k],anc[r-(1<<k)+1][k]);
}
int main() {
n=read();
m=read();
for(int i=1;i<=n;i++) {
anc[i][0]=read();
}
for(int i=2;i<=n;i++) logn[i]=logn[i/2]+1;
for(int i=1;(1<<i)<=n;i++) {
for(int j=1;j+(1<<i)-1<=n;j++) {
anc[j][i]=max(anc[j+(1<<(i-1))][i-1],anc[j][i-1]);
}
}
for(int i=1;i<=m;i++) {
int l=read(),r=read();
printf("%d\n",querymax(l,r));
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?