单调栈与单调队列 学习笔记

单调栈

概述

单调栈是一种特殊的,满足单调性的栈。单调栈插入元素时,不断弹出不满足单调性的元素。比如当前栈为 \(4,2,1\),插入 \(3\) 时要弹出 \(2,1\)

单调栈维护的是当前的后缀最大值,因此当新元素入栈时间更晚,值更大,就要出栈。

单调递减栈代码:

for(int i=1;i<=n;i++){
  while(cnt&&st[cnt]<=a[i])cnt--;
  st[++cnt]=a[i];
}

例题

P2866

问题可以转化为每头牛被几头牛看到。维护一个单调栈,根据定义,当一头牛入栈时,栈中都为后缀最大值,也就是说能看到新加入的牛。

此处高度相等的奶牛也会阻挡,因此单调栈是严格递减的。

代码:

#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++;
}

例题

P1886

单调栈板子。因为单调队列有单调性,因此队尾就是区间的极值。

代码:

#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;
}

[[数据结构]]

posted @ 2024-03-01 09:29  lgh_2009  阅读(8)  评论(0)    收藏  举报