单调队列和单调栈

所谓单调,就是容器中的数据是递增或递减的。

单调队列

 单调队列中数据要么是递增的,要么是递减的。
对于递减的单调队列,每次队尾加入一个数据,就把前面比它大的数从队尾弹出,然后再将本数据加入队列。

比如对于队列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;
} 

例题

求m区间内的最小值

几乎是模板题

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

例题

POJ Bad Hair Day

#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;    
}
原文地址:https://www.cnblogs.com/bennettz/p/7608796.html