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

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