单调栈
单调栈
定义
一种栈,其中的元素满足单调性
解决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] 差异 提示:后缀数组,单调栈

浙公网安备 33010602011771号