ST表-RMQ问题(洛谷P3865)

前置芝士用倍增思想求静态区间最值(无法求和)。dp[i][k]dp[i][k]dp[i][k]表示区间[i,i+2k−1][i,i+2^k-1][i,i+2k−1]的最大或最小值。预处理O(nlog⁡n)O(n\log n)O(nlogn)则dp[i][0]=a[i]dp[i][0]=a[i]dp[i][0]=a[i]。则:dp[i][j]=min/max(dp[i][j−1],dp[i+2j−1][j−1])dp[i][j]=min/max(dp[i][j-1],dp[i+2^{j-1}][j
摘要由CSDN通过智能技术生成

前置芝士

用倍增思想求静态区间最值(无法求和)。

d p [ i ] [ k ] dp[i][k] dp[i][k]表示区间 [ i , i + 2 k − 1 ] [i,i+2^k-1] [i,i+2k1]的最大或最小值。


预处理 O ( n log ⁡ n ) O(n\log n) O(nlogn)

d p [ i ] [ 0 ] = a [ i ] dp[i][0]=a[i] dp[i][0]=a[i]。则:
d p [ i ] [ j ] = m i n / m a x ( d p [ i ] [ j − 1 ] , d p [ i + 2 j − 1 ] [ j − 1 ] ) dp[i][j]=min/max(dp[i][j-1],dp[i+2^{j-1}][j-1]) dp[i][j]=min/max(dp[i][j1],dp[i+2j1][j1])

  • 要注意边界是 i + 2 j − 1 < = n i+2^j-1<=n i+2j1<=n,即当前枚举到的区间右端点不能超过 n n n,否则会指针乱跑访问非法空间。
  • 要先枚举 j j j,再循环 i i i,否则会访问到未处理区间。

其意义是对于 [ i , i + 2 j − 1 ] [i,i+2^j-1] [i,i+2j1]这个区间,将其拆分成前后两段2的次幂的,如图。
在这里插入图片描述


查询 O ( 1 ) O(1) O(1)

k = log ⁡ 2 ( r − l + 1 ) k=\log_2(r-l+1) k=log2(rl+1),即长度不超过总长的最大2的次幂的长度。则:
Q ( l , r ) = m a x / m i n ( d p [ l ] [ k ] , d p [ r − 2 k + 1 ] [ k ] ) Q(l,r)=max/min(dp[l][k],dp[r-2^k+1][k]) Q(l,r)=max/min(dp[l][k],dp[r2k+1][k])
查询时从左端点向左查最大不超过总长的2的次幂,与从右端点向左查同长,再将两个答案取最值即可。
在这里插入图片描述


参考代码(模板题)

#include<bits/stdc++.h>
#define ll long long//记得开long long
using namespace std;
const int MAXN=1e5+10;
int Q,a[MAXN],dp[MAXN][20],n;
void init(){
	for(int i=1;i<=n;i++) dp[i][0]=a[i];
	for(int j=1;j<20;j++)//j的上限为logn,需要灵活调整
		for(int i=1;i+(1<<j)-1<=n;i++)
			dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int LOG[MAXN];
int query(int l,int r){
	int k=LOG[r-l+1];
	return max(dp[l][k],dp[r-(1<<k)+1][k]);
}
int main()
{
	for(int i=0;i<1e5;i++) LOG[i]=log2(i);
	scanf("%d%d",&n,&Q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	init();int l,r;
	while(Q--){
		scanf("%d%d",&l,&r);
		printf("%d\n",query(l,r));
	}
}

使用注意事项

千万不要 M L E MLE MLE,宁可 R E RE RE少拿几个点也不要冲内存的极限。
注意边界

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值