ST表

定义

ST 表(Sparse Table,稀疏表)是用于解决 可重复贡献问题 的数据结构。------OI Wiki

可重复贡献问题是什么我也不知道

作用

静态区间最大(小)值,即一个区间不会修改。

能够实现 \\mathcal O(n\\log_2 n) 预处理,O(1) 查询

实现

倍增思想

\\large f_{x,i} 表示区间 \[x,x+2\^i-1\]最大值 。(最小值同理,下文不再赘述)

那么显然有:

\\large f_{x,0}=a_x

不难发现,\[l,l+2\^p\] 的区间最大值是区间 \[l,l+2\^{p-1}\] 和区间 \[l+2^{p-1}+1,l+2^p\] 的最大值。那么 \\large f_{x,i} 的转移方程就有(i\>0):

\\large f_{x,i}=\\max(f_{x,i-1},f_{x+2\^{i-1},i-1})

其实和倍增LCA的转移方程很像虽然倍增算法基本都长这样,一同理解倍增可能会好一些。

预处理

设数组 f\[x\]\[i\],定义同 f_{x,i}

那么预处理部分的代码就很简单了:

cpp 复制代码
void st_pre(){
	for(int i=0;i<=n;i++)lg[i]=lg[i/2]+1;//常数优化
	for(int i=1;i<=n;i++)f[i][0]=a[i];
	for(int i=1;i<=lg[n];i++){//循环顺序不能改!!
		for(int x=1;x+(1<<i)-1<=n;x++){
			f[x][i]=max(f[x][i-1],f[x+(1<<i-1)][i-1]);//状态转移方程
		}
	}
}

其中,lg\[i\] 表示 \\log_2i+1

时间复杂度:\\mathcal O(n\\log_2 n)

查询

ST表可以实现 \\mathcal O(1) 查询,实现如下:

询问区间 \[l,r\] 时,我们只需要返回区间 \\large\[l,s\] 和区间 \\large\[r-2\^s+1,r\] 的最大值即可,其中 s=\\lfloor \\log_2(r-l+1)\\rfloor(区间长度的对数)。

其实这样分成的两个区间会有重复部分(一定覆盖了 \[l,r\]),但是并不影响我们求区间最大值。

查询代码也很简单:

cpp 复制代码
int l,r;
scanf("%d %d",&l,&r);
int s=log2(r-l+1);
printf("%d\n",max(f[l][s],f[r-(1<<s)+1][s]));

例题

洛谷P3865

【模板】ST 表 && RMQ 问题

ST表模板题,虽然时限 800\\text{ms},但不加快读也能过。参考代码:

cpp 复制代码
//#include<bits/stdc++.h>
#include<algorithm> 
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
const int N=1e5;
int n,m,a[N+1],lg[N+1],f[N+1][(int)log2(N)+1]; 
void st_pre(){
	for(int i=0;i<=n;i++)lg[i]=lg[i/2]+1;
	for(int i=1;i<=n;i++)f[i][0]=a[i];
	for(int i=1;i<=lg[n];i++){
		for(int x=1;x+(1<<i)-1<=n;x++){
			f[x][i]=max(f[x][i-1],f[x+(1<<i-1)][i-1]);
		}
	}
}
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",a+i);
	st_pre();
	while(m--){
		int l,r;
		scanf("%d %d",&l,&r);
		int s=log2(r-l+1);
		printf("%d\n",max(f[l][s],f[r-(1<<s)+1][s]));
	}
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}
相关推荐
让我们一起加油好吗1 个月前
【基础算法】倍增
数学·算法·快速幂·洛谷·倍增
已经成为了代码的形状8 个月前
数据结构——ST表
数据结构·算法·st表
rgw20101 年前
P1081 [NOIP2012 提高组] 开车旅行
动态规划·dp·倍增·noip·倍增优化 dp
EQUINOX11 年前
二分+ST表+递推,Cf 1237D - Balanced Playlist
算法·动态规划·st表
卡布叻_周深1 年前
后缀数组 学习笔记
字符串·双指针·单调栈·并查集·st表·单调队列·后缀数组·分块与莫队
明朗晨光2 年前
【蓝桥】小蓝的疑问
线段树·二分查找·dfs·优先队列·st表·蓝桥·启发式合并
Qres8212 年前
长链贪心+虚树+类直径合并性+分块建树维护ST表:1008T4
数据结构·分块·直径·长链贪心·序树·st表·树剖
小威W2 年前
【算法】树上倍增 & LCA
算法···lca·倍增·树上倍增·最近公共祖先
昂昂累世士2 年前
leetcode 第360场周赛
dp·倍增