单调栈与单调队列 学习笔记
单调栈
概述
单调栈是一种特殊的,满足单调性的栈。单调栈插入元素时,不断弹出不满足单调性的元素。比如当前栈为 \(4,2,1\),插入 \(3\) 时要弹出 \(2,1\)。
单调栈维护的是当前的后缀最大值,因此当新元素入栈时间更晚,值更大,就要出栈。
单调递减栈代码:
for(int i=1;i<=n;i++){
while(cnt&&st[cnt]<=a[i])cnt--;
st[++cnt]=a[i];
}
例题
问题可以转化为每头牛被几头牛看到。维护一个单调栈,根据定义,当一头牛入栈时,栈中都为后缀最大值,也就是说能看到新加入的牛。
此处高度相等的奶牛也会阻挡,因此单调栈是严格递减的。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,st[80005],cnt;
long long ans;
int main(){
cin>>n;
for(int i=1,t;i<=n;i++){
cin>>t;
while(cnt&&st[cnt]<t)cnt--;
ans+=cnt,st[++cnt]=t;
}
return cout<<ans<<'\n',0;
}
单调队列
概述
类似地,单调队列是一种满足单调性的双端队列,插入元素时也会将队首不满足单调性的元素出队。与单调栈相比,单调队列还用把不在当前区间的数出队。
单调队列通常用于解决滑动窗口问题。若查询区间的左右端点单调不降就可以用单调队列 \(O(n)\) 解决。
单调递减队列代码:
for(int i=1,f=1,b=0;i<=n;i++){
while(f>=b&&a[q[f]]<=a[i])f--;
q[++f]=i;
while(q[b]<=i-k)b++;
}
例题
单调栈板子。因为单调队列有单调性,因此队尾就是区间的极值。
代码:
#include<bits/stdc++.h>
using namespace std;
template<typename T>void in(T &a)
{
T ans=0;
bool f=0;
char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;
for(;c>='0'&&c<='9';c=getchar())ans=ans*10+c-'0';
a=(f?-ans:ans);
}
template<typename T,typename... Args>void in(T &a,Args&...args)
{
in(a),in(args...);
}
int n,k,a[1000005],q[1000005];
int main(){
in(n,k);
for(int i=1;i<=n;i++)in(a[i]);
for(int i=1,f=1,b=0;i<=n;i++){
while(f>=b&&a[q[f]]>a[i])f--;
q[++f]=i;
while(q[b]<=i-k)b++;
if(i>=k)cout<<a[q[b]]<<' ';
}
putchar('\n');
for(int i=1,f=1,b=0;i<=n;i++){
while(f>=b&&a[q[f]]<a[i])f--;
q[++f]=i;
while(q[b]<=i-k)b++;
if(i>=k)cout<<a[q[b]]<<' ';
}
return 0;
}
[[数据结构]]

浙公网安备 33010602011771号