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;
}

浙公网安备 33010602011771号