NIYAXIMEN

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  13 随笔 :: 0 文章 :: 0 评论 :: 238 阅读

ST表

\(RMQ\),支持查询一个静态数组的区间最大值,不支持修改操作

预处理:\(o(n*lgn)\)

查询:\(o(1)\)

预处理

\(ST\)表的基本思想是倍增,预处理类似于区间\(dp\)问题

定义\(f[i][j]\)为从下标为\(i\)的元素开始,向后扩展\(2^{j}\)的距离的区间内的最大值,即\([i,i+2^j-1]\)内的最大值

转移方程类似于区间\(dp\)问题,可以从更小的区间内得到,将该区间分为两端,得到转移方程

\[f[i][j]=max(f[i][j-1],f[i+2^{j-1}][j-1]) \]

求解这个问题也就是区间\(dp\)的问题,先枚举区间长度\(j\),再枚举\(i\)

下面是边界问题,明显遍历到\(n\)会超出界限

对于\(f[i][j]\)最远会扩展到\(i+2^j-1\)的距离,所以有

\[i+2^j-1\leq n \]

对于\(j\)的范围

\[min(i+2^j-1)\leq n\\ i=1\\ 2^j \leq n\\ j \leq log_{2}^{n}\\ \]

    for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;//打表预处理lg[n]
	for(int i=1;i<=n;i++)scanf("%d",&f[i][0]);
	for(int j=1;j<=lg[n];j++)
	{
		for(int i=1;i<=n-(1<<j)+1;i++)
		{
			f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);//位运算要注意括号
		}
	}

区间查询

现在,给出一段区间\([l,r]\),要在\(ST\)表内找到一段可以覆盖这段距离的,最大的子区间

\[l+2^k-1 \leq r\\ 2^k \leq r-l+1\\ k \leq lg[r-l+1] \]

这里直接令\(j=k\)

求出第一个子区间为\(f[l][k]\)

对于第二个子区间,可以以\(r\)为终点,反向找到一个子区间根据对称,\(k\)显然是不变的,由于\(r-1 \leq l+2^k-1\leq r\)

这样处理是一定可以将区间覆盖的

设第二个子区间起始的下标为\(D\)

\[D+2^k-1=r\\ D=r-2^k+1 \]

因此,区间\([l,r]\)的最大值即为

\[k=lg[r-l+1]\\ max(f[l][k],f[r-(l<<k)+1][k]) \]

CODE

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int f[N][20],lg[N];
int n,m;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
	for(int i=1;i<=n;i++)scanf("%d",&f[i][0]);
	for(int j=1;j<=lg[n];j++)
	{
		for(int i=1;i<=n-(1<<j)+1;i++)
		{
			f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
		}
	}
	while(m--)
	{
		int l,r;scanf("%d%d",&l,&r);int k=lg[r-l+1];
		int ans=max(f[l][k],f[r-(1<<k)+1][k]);
		printf("%d\n",ans);
	}
}

原题链接:P3865 【模板】ST 表 && RMQ 问题 - 洛谷 | 计算机科学教育新生态

参考:【模板】ST表图解 - 洛谷专栏

posted on   AsukaAlice  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示