单调队列、单调栈、优先队列模板

目录

  • 单调栈、单调队列及优先队列

    • 1.单调队列
    • 2.单调栈
    • 3.优先队列

单调栈、单调队列及优先队列

1.单调队列

单调队列的描述:指队列中元素之间关系具有单调性,而且队首和队尾都可以出队,但是只有队尾可以进行入队操作。其重要作用是找到前n个后者后n个数的最值。

其具体操作是:假设单调队列是单调递减队列,假设在插入元素v时,将队列尾部的元素同v比较,如果队列尾部的元素不大于元素v,我们直接删除队尾元素,再将队尾元素与v比较,直至队尾元素比v大,这个时候我们将v插入队尾。其实现代码如下:

int que[100];
int head = 0, tail = 0;
void push(int a)            //进队
{
    que[++tail] = a;
}
int pop()                 //出队
{
    return que[++head];
}
bool empty()                //判断队列是否为空
{
    return !(head < tail);
}

下面是求一个整数序列中每k个中的最大值和最小值的代码:

#include<iostream>
#include<cstdio>

using namespace std;
const int maxn=1e6+10;
int arr[maxn],que[maxn];

int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i)
        scanf("%d",&arr[i]);
    int head=1,tail=0;
    for(int i=1;i<=n;++i){
        if(i==1){
            que[++tail]=i;
        }
        else{
            while(head<=tail&&arr[i]<arr[que[tail]])   tail--;
            que[++tail]=i;
            if(que[tail]-que[head]>=k)   head++;
        }
        if(i>=k)   printf("%d ",arr[que[head]]);
    }
    printf("\n");
    head=1,tail=0;
    for(int i=1;i<=n;++i)
    {
        if(i==1)    que[++tail]=i;
        else{
            while(head<=tail&&arr[i]>arr[que[tail]]) tail--;
            que[++tail]=i;
            if(que[tail]-que[head]>=k)   head++;
        }
        if(i>=k)    printf("%d ",arr[que[head]]);
    }
    printf("\n");
}

2.单调栈

顾名思义,单调栈也是保持栈内元素单调递增或单调递减。在插入元素时仍需保持栈内元素的单调性。如现有单调栈,其栈内元素为:1 4 5,这时我们将元素3插入单调栈的话;我们需要先将4 5弹出栈在将3入栈,操作之后栈内元素变为1 3。单调栈似乎也可以通过单调队列实现...

stack<int> S;
for(int i=1 ;i<=n ;i++){
    while(S.size() && a[S.top()] >= a[i]) S.pop();

    if(S.empty())     L[i] = 0;
    else              L[i] = S.top();

    S.push(i);
}

代码:求最大矩形面积:

#include<bits/stdc++.h>

using namespace std;
const int maxn = 2010;
typedef long long ll;
int arr[maxn][maxn], top, st[maxn];
int ans;
int L[maxn], R[maxn];

int main()
{
    //ios::sync_with_stdio(false);
    int n,m;
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        memset(R,0,sizeof(R));
        memset(L,0,sizeof(L));
        memset(st,0,sizeof(st));
        for (int i=1;i<=n;++i)
            for (int j=1;j<=m;++j)
                scanf("%d",&arr[i][j]);
        for (int i =n-1;i>=1;--i)
            for (int j=1;j<=m;++j)
                if(arr[i][j])
                    arr[i][j]+=arr[i+1][j];
        ans=-0x3f3f3f3f;
        for(int i=1;i<=n;++i)
        {
            top=0;
            for(int j=1;j<=m;++j)
            {
                while(top>=1&&arr[i][j]<=arr[i][st[top]])
                    top--;
                if(!top)
                    L[j]=1;
                else
                    L[j]=st[top]+1; //在栈顶元素后一位
                st[++top]=j;
            }
            top = 0;
            for(int j=m;j>= 1;--j)
            {
                while(top>=1&&arr[i][j]<=arr[i][st[top]])
                    top--;
                if (!top)
                    R[j]=m;
                else
                    R[j]=st[top]-1; //在栈顶元素前一位,减一个1
                st[++top]=j;
            }
            for(int j=1;j<=m;++j)
                ans=max(ans,arr[i][j]*(R[j]-L[j]+1));
        }
        printf("%d\n",ans);
    }
}

上面求的是最左边第一个比该数小和最右边第一个比该数小的用法,如果要求最右边或最右边第一个比该元素大,只需将while循环里面的<=改为>即可.

#include<bits/stdc++.h>

using namespace std;
const int maxn=1e5+10;
typedef long long ll;
ll arr[maxn],n;
ll st[maxn],L[maxn],R[maxn],top;

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
        scanf("%d",&arr[i]);
    top=0;
    for(int i=1;i<=n;++i)
    {
        while(top>=1&&arr[i]>arr[st[top]])
            top--;
        if(!top)    L[i]=i;
        else        L[i]=st[top];
        st[++top]=i;
    }
    top=0;
    for(int i=n;i>=1;--i)
    {
        while(top>=1&&arr[i]>arr[st[top]])
            top--;
        if(!top)    R[i]=i;            //如果该元素作为次大值没有比它大的,那么最大值和次大值都是它本身
        else        R[i]=st[top];      //这里不需要加1或者减1,因为这就是比它大的第一个值的下标
        st[++top]=i;
    }
    ll res=-0x3f3f3f3f;
    for(int i=1;i<=n;++i){
        res=max(res,max(arr[i]^arr[L[i]],arr[i]^arr[R[i]]));
    }
    printf("%d\n",res);
    system("pause");
}

3.优先队列

优先队列是一个队列,优先级高的会先出队列,用法实例:

priority_queue<int> a;
priority_queue<node> b;
priority_queue<int,vector<int>,greater<int> > c;        //注意最后两个>>不能写在一起,加个空格,否则是右移符号,与greater相似的还有less<int>...

在默认情况下,优先队列会自动按降序(从大到小的顺序排列),less是从大到小,greater是从小到大,下面介绍优先队列的结构体用法和堆用法:

1.优先队列装结构体

有两种排序方式,在结构体外面和在结构体里面:

struct node
{
    int x;
    int y;
    bool operator < (cosnt node& t){
        return x>t.x;
    }
}
bool operator < (const node& a,const node& b)
{
    return a.x>b.x;
}                                       //在结构体外面的写法,上例会先输出x较小的

下面是例题代码:

#include<bits/stdc++.h>

using namespace std;
int n,doct;
struct node
{
    int id;     //编号
    int q;      //优先级
    friend bool operator < (const node& a,const node& b)
    {
        if(a.q==b.q)    return a.id>b.id;
        return a.q<b.q;
    }           //优先级别排序
}pat;
priority_queue<node> arr[4];

int main()
{
    ios::sync_with_stdio(0);
    string str;
    int cnt=1;
    while(cin>>n&&n)
    {
        cnt=1;
        for(int i=1;i<=3;i++)
        {
            while(!arr[i].empty())
                arr[i].pop();
        }                           //初始化
        while(n--)
        {
            cin>>str;
            if(str=="IN"){
                cin>>doct>>pat.q;
                pat.id=cnt++;
                arr[doct].push(pat);
            }
            else{
                cin>>doct;
                if(arr[doct].empty())
                    cout<<"EMPTY"<<endl;
                else{
                    cout<<arr[doct].top().id<<endl;
                    arr[doct].pop();
                }
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/StungYep/p/12254035.html

时间: 2024-10-11 11:40:07

单调队列、单调栈、优先队列模板的相关文章

单调队列单调栈

单调队列单调栈 Tags:数据结构 更好阅读体验:https://www.zybuluo.com/xzyxzy/note/1041449 一.概述 单调队列单调栈是很基础的数据结构,常用来优化一些东西比如说优化DP 那么大概意思就是在栈或队列中按照某关键字单调维护信息,从而实现一些功能 其实很久之前接触过单调队列和单调栈,但一直没有刷题,趁这两天被LCT弄晕的时候复习下这些 先看题 二.题单 普及- [x] P1886 滑动窗口 https://www.luogu.org/problemnew/

模板 - 数据结构 - 单调队列/单调栈

一道例题,给定一串数字,求每连续k个数字的最大.最小值. 思路:初始化一个初始长度为k的单调队列,按从左到右加入元素,同时满足这个队列中的元素是递减的(也就是假如某个数被两个距离不超过k的大于他的数夹着,他会被从队尾调出队列).得到最大值. 向右移动一格,假如队首离开范围,出队.往队尾加入元素前,把队尾的所有比它小的元素全部出队. 得到新的最大值. #include<bits/stdc++.h> using namespace std; struct Monotone_Queue{ deque

单调队列 单调栈

建议不了解STL的读者先了解几个基本的队列的STL.这也是单调队列和单调栈一般都会用到的. 单调队列:建立一个队列,使队列一直具有单调性(满足单调递增或者单调递减),时间复杂度O(N). 那么我们应该如何做到"使队列一直具有单调性"呢? 以单调递增为例,我们O(N)扫描整个序列,每扫描到一个元素: 1 如果该元素大于等于队列末尾元素,则直接入队; 2 而如果该元素小于已有队列的末尾元素,即不满足单调递增,则使队列中的末尾元素出队,直到该元素符合入队条件,然后入队. 如果只到这里,那么我

【NOIP数据结构专项】单调队列单调栈

[洛谷P1901 ]发射站 http://www.luogu.org/problem/show?pid=1901 题目描述 某地有 N 个能量发射站排成一行,每个发射站 i 都有不相同的高度 Hi,并能向两边(当 然两端的只能向一边)同时发射能量值为 Vi 的能量,并且发出的能量只被两边最近的且比 它高的发射站接收. 显然,每个发射站发来的能量有可能被 0 或 1 或 2 个其他发射站所接受,特别是为了安 全,每个发射站接收到的能量总和是我们很关心的问题.由于数据很多,现只需要你帮忙计 算出接收

小Z爱序列(NOIP信(sang)心(bin)赛)From Fall_Dream(粗制单调队列&amp;单调栈的算法解析)

原题: 小Z最擅长解决序列问题啦,什么最长公共上升然后下降然后上升的子序列,小Z都是轻松解决的呢. 但是小Z不擅长出序列问题啊,所以它给了你一道签到题. 给定一个n个数的序列ai,你要求出满足下述条件的点对的数量. 假设点对是(i , j),max(l,r)是[l,r]当中最大的ai的值. 这个点对满足条件当且仅当i+1<j 且 ai < max(i+1,j-1) < aj 为了简单,保证输入的是一个1-n的排列.相信你已经会做了吧? 输入/输出格式 输入数据第一行有一个数字n,然后第二

单调队列&amp;单调栈归纳

单调队列 求长度为M的区间内的最大(小)值 单调队列的基本操作,也就是经典的滑动窗口问题. 求长度为M的区间内最大值和最小值的最大差值 两个单调队列,求出长度为M的区间最大最小值的数组,分别求最大最小值. 求边长为a的正方形内最大值和最小值的最大差值([HAOI2007]理想的正方形) 一个大体的思路是先分别求出以i,j为左上端点的边长为a的矩形中的最大值和最小值.那么该怎么做?,先用单调队列求出一个点右边a个单位的最大值,形成一个新矩阵,再求出新矩阵下边a个单位的最大值.然后最小值再求一边,最

单调队列/单调栈入门详解+题目推荐

以前一直以为这两个是很高级的东西,这段时间用到了才开始学,发现实际上非常简单 下面我们以单调队列为例进行讲解,单调栈自行类比 顾名思义 单调队列这个名字就指明了它的性质--单调性 我们来看一道例题--滑动窗口 题面在此不再赘述,大意就是有一个长度为\(n\)的数列,一个长度为\(k\)的窗口,输出窗口位于每个位置下的下的最大最小值 嗯,题目很好理解,st表或者线段树过的先别说话,我们来看看另一种方法 我们维护一个长度为k的队列,使得队列的开头为答案,那么我们每次只需要输出开头就好了.这个想法很好

[hdu1506]单调队列(栈)

题意:http://acm.hdu.edu.cn/showproblem.php?pid=1506看图一目了然.两个方向单调队列维护下. 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstdlib> 5 #include <cstring> 6 #include <map> 7 #include <queue> 8

手工 stack栈 queue队列 priority queue 优先队列 模板

栈stack: 1 struct sta 2 { 3 int sz[100001]; 4 int top() 5 { 6 return sz[top]; 7 } 8 void push(int x){ 9 sz[++top]=x; 10 } 11 void pop(){ 12 if(top>0) 13 top--; 14 } 15 void cl() 16 { 17 top=0; 18 } 19 int size(){ 20 return top; 21 } 22 }stack;