单调栈&单调队列

单调栈

定义

   单调栈是指一个栈内部的元素是具有严格单调性的一种数据结构,分为单调递增栈和单调递减栈。

性质:
   ① 满足从栈顶到栈底元素具有严格的单调性。
   ② 满足栈的后进先出特性,越靠近栈底的元素越早进栈。

单调队列

定义:

   单调队列是指一个队列内部的元素具有严格单调性的一种数据结构,分为单调递增队列和单调递减队列。

性质:
   ① 单调队列必须满足从队头到队尾的严格单调性。
   ② 满足队列的先进先出特性,排在队列前面的比排在队列后面的要先出队。

练习

   单调栈和单调队列可以用STL中的stack(栈)和deque(双端队列)实现,也可以手写数组实现并且因为数据只会进出至多一次,所以不会超限。

   单调栈&单调队列的思想和实现都比较简单,可以试做以下例题去体验这种思想。

单调栈:

poj 3250  Bad Hair Day

#include<iostream>
#include<cstdio>
#include<stack>
using namespace std;
int const maxn=80005;
long long h[maxn],sum;
stack<long long> sta;
int main()
{
  int n,i;
  scanf("%d",&n);
  for(i=1;i<=n;i++) scanf("%lld",&h[i]);
  for(i=1;i<=n;i++)
  {
    while(!sta.empty()&&h[i]>=h[sta.top()]) sta.pop();
    sum+=sta.size();
    sta.push(i);
  }
  printf("%lld
",sum);
  return 0;
}
View Code

poj 2796  Feel Good

#include<iostream>
#include<cstdio>
#include<stack>
using namespace std;
int const maxn=100005;
long long w[maxn],sum[maxn];
int L[maxn],R[maxn];
stack<long long> sta;
int main()
{
  int n,i,l,r;
  long long ans=-1;
  scanf("%d",&n);
  for(i=1;i<=n;i++) scanf("%lld",&w[i]),sum[i]=sum[i-1]+w[i];
  for(i=n;i>=1;i--)
  {
    while(!sta.empty()&&w[i]<w[sta.top()]) 
     L[sta.top()]=i+1,sta.pop();
    sta.push(i);
  }
  while(!sta.empty()) L[sta.top()]=1,sta.pop();
  for(i=1;i<=n;i++)
  {
    while(!sta.empty()&&w[i]<w[sta.top()]) 
     R[sta.top()]=i-1,sta.pop();
    sta.push(i);
  }
  while(!sta.empty()) R[sta.top()]=n,sta.pop();
  for(i=1;i<=n;i++)
  {
    if(ans<w[i]*(sum[R[i]]-sum[L[i]-1]))
     {
       l=L[i];
       r=R[i];
       ans=w[i]*(sum[R[i]]-sum[L[i]-1]);
     }
  }
  printf("%lld
%d %d
",ans,l,r);
  return 0;
}
View Code

poj 2559  Largest Rectangle in a Histogram

#include<iostream>
#include<cstdio>
#include<stack>
using namespace std;
struct node
{
  int w;
  long long h;
  node(){}
  node(int a,long long b)
  {w=a;h=b;}
};
int const maxn=100005;
long long h[maxn];
int main()
{
  int n,i;
  long long ans;
  while(scanf("%d",&n)&&n)
  {
    stack<node> sta;
    ans=-1;h[n+1]=0;
    for(i=1;i<=n;i++) scanf("%lld",&h[i]);
    for(i=1;i<=n+1;i++)
    {
      if(sta.empty()||h[i]>sta.top().h) sta.push(node(1,h[i]));
      else
      {
        int t=0;
        while(!sta.empty()&&h[i]<=sta.top().h)
        {
         t+=sta.top().w;
         ans=max(ans,sta.top().h*t);
         sta.pop();
        }
        sta.push(node(t+1,h[i]));
      }
    }
    printf("%lld
",ans);
}
  return 0;
}
View Code

单调队列:

hdu 3530  Subsequence

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn=100010;
deque <int> quemax,quemin;
int w[maxn];
int main()
{
  int i,n,m,k,ans,cnt;
  while(~scanf("%d%d%d",&n,&m,&k))
  {
    quemax.clear();quemin.clear();ans=0;cnt=0;
    for(i=1;i<=n;i++) scanf("%d",&w[i]);
    for(i=1;i<=n;i++)
    {
      while(!quemax.empty()&&w[i]>w[quemax.back()]) quemax.pop_back();
      quemax.push_back(i);
      while(!quemin.empty()&&w[i]<w[quemin.back()]) quemin.pop_back();
      quemin.push_back(i);
      while(!quemax.empty()&&!quemin.empty()&&w[quemax.front()]-w[quemin.front()]>k)
      {
        if(quemax.front()<quemin.front())
         cnt=quemax.front(),quemax.pop_front();
        else
         cnt=quemin.front(),quemin.pop_front();
      }
      if(!quemax.empty()&&!quemin.empty()&&w[quemax.front()]-w[quemin.front()]>=m) ans=max(ans,i-cnt);
    }
    printf("%d
",ans);
  }
  return 0;
}
View Code

poj 2823  Sliding Window

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn=1000005;
deque <int> quemax,quemin;
int w[maxn],mmax[maxn],mmin[maxn];
int main()
{
  int i,n,k;
  while(~scanf("%d%d",&n,&k))
  {
    quemax.clear();quemin.clear();
    for(i=1;i<=n;i++) scanf("%d",&w[i]);
    for(i=1;i<=n;i++)
    {
      while(!quemax.empty()&&w[i]>w[quemax.back()]) quemax.pop_back();
      quemax.push_back(i);
      while(!quemax.empty()&&quemax.front()<=i-k) quemax.pop_front();
      mmax[i]=w[quemax.front()];

      while(!quemin.empty()&&w[i]<w[quemin.back()]) quemin.pop_back();
      quemin.push_back(i);
      while(!quemin.empty()&&quemin.front()<=i-k) quemin.pop_front();
      mmin[i]=w[quemin.front()];
    }
    for(i=k;i<=n;i++)
     printf("%d%c",mmin[i],i==n?'
':' ');
    for(i=k;i<=n;i++)
     printf("%d%c",mmax[i],i==n?'
':' ');
  }
  return 0;
}
View Code

洛谷 P2032  扫描

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int const maxn=2*1e6+5;
int w[maxn],mmax[maxn];
deque<int> que;
int main()
{
  int i,n,k;
  scanf("%d%d",&n,&k);
  for(i=1;i<=n;i++) scanf("%d",&w[i]);
  for(i=1;i<=n;i++)
  {
    while(!que.empty()&&que.front()<=i-k) que.pop_front();
    while(!que.empty()&&w[i]>w[que.back()]) que.pop_back();
    que.push_back(i);
    mmax[i]=w[que.front()];
  }
  for(i=k;i<=n;i++) printf("%d
",mmax[i]);
  return 0;
}
View Code

洛谷 P1714  切蛋糕

#include<bits/stdc++.h>
using namespace std;
int const maxn=500005;
int sum[maxn];
deque<int> que;
int main()
{
  int n,m,x,i,ans=-1;
  scanf("%d%d",&n,&m);
  for(i=1;i<=n;i++) scanf("%d",&x),sum[i]+=sum[i-1]+x;
  for(i=1;i<=n;i++)
  {
    while(!que.empty()&&que.front()<i-m) que.pop_front(); 
    while(!que.empty()&&sum[i]<sum[que.back()]) que.pop_back();
    que.push_back(i);
    ans=max(ans,sum[i]-sum[que.front()]);
  }
  printf("%d
",ans);
  return 0;
}
View Code

洛谷 P2947  Look Up

#include<bits/stdc++.h>
using namespace std;
int const maxn=100005;
int h[maxn],ans[maxn];
stack<int> sta;
int main()
{
  int n,i;
  scanf("%d",&n);
  for(i=1;i<=n;i++) scanf("%d",&h[i]);
  for(i=1;i<=n;i++)
  {
    while(!sta.empty()&&h[i]>h[sta.top()])
    {
      ans[sta.top()]=i;
      sta.pop();
    }
    sta.push(i);
  }
  while(!sta.empty()) ans[sta.top()]=0,sta.pop();
  for(i=1;i<=n;i++) printf("%d
",ans[i]);
  return 0;
}
View Code
本博客仅为本人学习,总结,归纳,交流所用,若文章中存在错误或有不当之处,十分抱歉,劳烦指出,不胜感激!!!
原文地址:https://www.cnblogs.com/VividBinGo/p/11384066.html