单调栈
定义:
单调栈是指一个栈内部的元素是具有严格单调性的一种数据结构,分为单调递增栈和单调递减栈。
性质:
① 满足从栈顶到栈底元素具有严格的单调性。
② 满足栈的后进先出特性,越靠近栈底的元素越早进栈。
单调队列
定义:
单调队列是指一个队列内部的元素具有严格单调性的一种数据结构,分为单调递增队列和单调递减队列。
性质:
① 单调队列必须满足从队头到队尾的严格单调性。
② 满足队列的先进先出特性,排在队列前面的比排在队列后面的要先出队。
练习
单调栈和单调队列可以用STL中的stack(栈)和deque(双端队列)实现,也可以手写数组实现并且因为数据只会进出至多一次,所以不会超限。
单调栈&单调队列的思想和实现都比较简单,可以试做以下例题去体验这种思想。
单调栈:

#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\n",sum); return 0; }

#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\n%d %d\n",ans,l,r); return 0; }
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\n",ans); } return 0; }
单调队列:

#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\n",ans); } return 0; }

#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?'\n':' '); for(i=k;i<=n;i++) printf("%d%c",mmax[i],i==n?'\n':' '); } return 0; }

#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\n",mmax[i]); return 0; }

#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\n",ans); return 0; }

#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\n",ans[i]); return 0; }