单调队列和单调栈
所谓单调,就是容器中的数据是递增或递减的。
单调队列
单调队列中数据要么是递增的,要么是递减的。
对于递减的单调队列,每次队尾加入一个数据,就把前面比它大的数从队尾弹出,然后再将本数据加入队列。
比如对于队列1,3,4,6,9,如果插入5,
就先比较5,9因为9>5,则9弹出队列,
再比较6,5,6>5,则6出队,
这时队列为1,3,4,比较4,5,4<5,则5入队
有时对于滑动窗口的题,单调队列还要存储它的加入顺序(可以证明这个数据是单调递增的)。
如果队首位置(当前队列中最早加入的数据)已经不属于滑动窗口,就将他从队首弹出。
比如对于二元组队列(1,1),(3,2),(4,3),(6,4),(9,5)。
注:第二个数据是加入队列的顺序,如果窗口长度是5,再加入(5,6);
队尾的变化同上,队列变为(1,1),(3,2),(4,3),(5,6);
这时最晚加入的数据和最早加入的跨度6已经大于窗口长度5,则队首数据(1,1)出队。
结构体代码(单调递减队列)
#include<cstdio> #define maxk 2000001//maxk为滑动窗口最长长度 struct HumdrumQueue{ int s,t,k,a[maxk],id[maxk];//a为存储数据,id为入队顺序,s,t分别为队首,队尾+1,k为滑动窗口长度 int top(){//返回队首 if(s==t)return 0;//为空就返回0 return a[s]; } void pop(){//队首出队 if(s!=t)s++; } void insert(int x,int i){//加入x,当前是第i个数据 while(s!=t&&a[t-1]>=x){//队尾不满足单调的出队 t--; if(t==-1)t=k; } if(i-id[s]>=k)pop();//队首如果不属于滑动窗口,则出队 a[t]=x,id[t++]=i,t%=maxk;//因为队列中元素不大于maxk,所以使用循环队列 } }q; int main(){ return 0; }
例题
几乎是模板题
#include<cstdio> #define maxk 2000001//maxk为滑动窗口最长长度 struct HumdrumQueue{ int s,t,k,a[maxk],id[maxk];//a为存储数据,id为入队顺序,s,t分别为队首,队尾+1,k为滑动窗口长度 int top(){//返回队首 if(s==t)return 0;//为空就返回0 return a[s]; } void pop(){//队首出队 if(s!=t)s++; } void insert(int x,int i){//加入x,当前是第i个数据 while(s!=t&&a[t-1]>=x){//队尾不满足单调的出队 t--; if(t==-1)t=k; } if(i-id[s]>=k)pop();//队首如果不属于滑动窗口,则出队 a[t]=x,id[t++]=i,t%=maxk;//因为队列中元素不大于maxk,所以使用循环队列 } }q; int main(){ int n,m,x;scanf("%d%d",&n,&m); q.k=m; for(int i=0;i<n;i++){ scanf("%d",&x); printf("%d\n",q.top()); q.insert(x,i); } return 0; }
单调栈
单调栈和单调队列差不多,分单调递增栈和单调递减栈,区别就是单调栈只能从栈顶弹出元素
- 单调递增栈,则从栈顶到栈底的元素是严格递增的
- 单调递减栈,则从栈顶到栈底的元素是严格递减的
#include<cstdio> #define maxn 1000005 struct MonotonicStack {//单调递增栈 int a[maxn],top; MonotonicStack(){ top=0; } void pop(){//栈顶弹出 if(top)top--; } int size(){//返回站内元素个数 return top; } void insert(int x){//插入x while(top&&a[top]<=x)top--;//将不满足单调的弹出 a[++top]=x; } }S; int main(){ return 0; }
例题
#include<cstdio> #define maxn 1000005 struct MonotonicStack {//单调递增栈 int a[maxn],top; MonotonicStack(){ top=0; } void pop(){//栈顶弹出 if(top)top--; } int size(){//返回站内元素个数 return top; } void insert(int x){//插入x while(top&&a[top]<=x)top--;//将不满足单调的弹出 a[++top]=x; } }S; long long sum; int main(){ int n,x;scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%d",&x); S.insert(x); sum+=S.size()-1; } printf("%lld",sum); return 0; }