单调栈

单调栈

定义

一种栈,其中的元素满足单调性

解决NGE问题

NGE问题(Next Greater Element)

#include<bits/stdc++.h>
using namespace std;

const int N=3e6+10;
int n;
int a[N],stk[N],f[N],tp;
int main(){
	cin>>n;
	for(int i=1;i<=n;++i)cin>>a[i];
	for(int i=1;i<=n;++i){
		while(tp>0&&a[stk[tp]]<a[i]){
			f[stk[tp]]=i;
			tp--;
		}
		stk[++tp]=i;
	}
	for(int i=1;i<=n;++i)printf("%d ",f[i]);puts("");
	return 0;
}

解决所有子数组min,max和的问题

给出一个数列,求所有连续子区间最小值之和

朴素算法:枚举左端点的暴力 \(n^2\)

上面算法仍然浪费了一部分复杂度,在于左端点从l到l+1时会重复计算。

接下来转变思路,统计一个数作为最小值在多少子数组里出现过,不妨设为 \(x\)

则找到左边第一个小于等于 \(x\) 的元素 \(y\) 下标为 \(L_i\),找到右边第一个小于 \(x\) 的元素 \(y\) 下标为 \(R_i\)

这样统计,\((R_i-x) \times (x-L_i)\ \ \ (1)\)即为所求。

证明:若有严格小于 \(x\) 的数在次序列内,一定不是要求的,上面算法已经去除。
对于序列内相同的元素,上面的算式只计算了x为所有等于x的元素的最后一个的值。而统计所有答案的时候,所有等于x的元素都会作为右端点,所以答案无误。
另请自行理解 \((1)\) 的含义,需要使用乘法原理,内容较为简单。

stk[tp=1]=1;
for(int i=2;i<=n;++i){
	while(tp>0&&ht[stk[tp]]>ht[i]){
		r[stk[tp]]=i;
		tp--;
	}
	l[i]=stk[tp];
	stk[++tp]=i;
}
while(tp>0)r[stk[tp--]]=n+1;

练习题

P4248 [AHOI2013] 差异 提示:后缀数组,单调栈

posted @ 2024-02-27 00:27  妖灵梦  阅读(15)  评论(0)    收藏  举报