【数据结构】单调栈和单调队列 详解+例题剖析

本文深入介绍了单调栈和单调队列的概念,强调了它们在维护元素单调性方面的重要性。通过模板题解析,展示了如何使用单调栈解决POI2008 PLA-Postering问题,以及单调队列在求解区间最小值和滑动窗口最大值等问题中的应用。文中还提醒在使用STL实现时需注意初始条件,并提供了错误案例以加深理解。
摘要由CSDN通过智能技术生成

一.单调栈和单调队列

单调栈和单调队列与普通的栈,队列不同点就是要维护他们元素的单调性(单增或单减),来实现相应的效果。要注意的是单调栈和单调队列即可以用数组模拟,也可以直接使用STL(更方便易于理解),但是如果用STL的话,单调栈/队列要在开始放入元素之前设置边界,单调递增就在边界(栈顶/队首)赋值为负值(<=0),单调递减就在边界赋值为INF(极大值)。因为如果栈/队列内无元素,那么s.top()是不合法的,这样就无法继续进行插入和删除操作来维护单调性。
如何维护单调:
每输入一个新元素就比较它是否符合单调要求,符合就push进去,不符合就把它前面的pop掉。
单调队列:
例如滑动窗口的要求要最多存几个元素,所以一旦越界就pop,一旦不单调就pop;
单调队列里新人是一定要进来的,老人可能都比新人弱而被全员踢出,但是踢干净以后立刻新人就push_back进来了,所以不会为空
具体的代码就直接看例题,相信您一看就懂。

二.单调栈例题

1.模板题入门

P3467 [POI2008]PLA-Postering
Byteburg市东边的建筑都是以旧结构形式建造的:建筑互相紧挨着,之间没有空间.它们共同形成了一条长长的,从东向西延伸的建筑物链(建筑物的高度不一).Byteburg市的市长Byteasar,决定将这个建筑物链的一侧用海报覆盖住.并且想用最少的海报数量,海报是矩形的.海报与海报之间不能重叠,但是可以相互挨着(即它们具有公共边),每一个海报都必须贴近墙并且建筑物链的整个一侧必须被覆盖(意思是:海报需要将一侧全部覆盖,并且不能超出建筑物链)
输入格式
The first line of the standard input contains one integer nnn (1≤n≤250 000), denoting the number of buildings the chain comprises of.
Each of the following nnn lines contains two integers did_idi​ and wiw_iwi​ (1≤di,wi≤1 000 000 000),
separated by a single space, denoting respectively the length and height of the ithi^{th}ith building in the row.
第一行为一个整数n(1≤n≤250000),表示有n个建筑,接下来n行中,第i行表示第i个建筑物的宽di与高wi(1≤di,wi≤1 000 000 000),中间由一个空格隔开
输出格式
The first and only line of the standard output should contain one integer, the minimum number of rectangular posters that suffice to cover the north faces of the buildings.
第一个为一个整数,表示最少需要几张海报.
输入

5
1 2
1 3
2 2
2 5
1 4

输出

 4
#include<bits/stdc++.h>
using namespace std;
int n,temp,a,b,cnt;
stack<int>s;
int main()
{
   
    cin>>n;
    s.push(-1);//设边界
    cin>>a>>b;//本题中宽度没用
    s.push(b);
    for(int i=2;i<=n;i++)
    {
   
        cin>>a>>b;
        while(s.top()>=b)//一旦单调(递增)被破坏就把大与新人的都pop掉
        {
   
            temp=s.top();
            if(temp==b)cnt++;//若有相同的则可以省一张海报
            s.pop();
        }
        s.push(b);
    }
    cout<<n-cnt<<endl;//输出共需多少张海报即可
    return 0;
}

2.不懂不要急,看这道题

单调栈这个东西还是很容易理解的,就是一个栈,维护好他的单调性,可以是单调递增也可以是单调递减(或者非严格单增等等 )。写起来非常好写, 就是如果当前要入栈的元素大于栈顶就push进去,如果小于就一直pop,直到当前元素大于栈顶元素或者栈空为止,很容易就可以证明/看出来这个栈依照这样的操作一定能保持单调。那么这样的单调栈到底有什么作用呢 ?比如下面这道题。
在这里插入图片描述
输入样例:

7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0

输出样例:

8
4000

这道题要求最大面积,看上去没什么思路,其实就是单调栈的最基本的应用。
我画几个图就能非常直观地感受这道题了,不过在此之前最好先看一下代码,然后再看图。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<math.h>
#include<stack>
#include<vector>

#define ls (p<<1)
#define rs (p<<1|1)
#define over(i,s,t) for(register int i=s;i<=t;++i)
#define lver(i,t,s) for(register int i=t;i>=s;--i)
//#define int __int128
using namespace std;
typedef pair<double,double> PDD;

typedef long long ll;//全用ll可能会MLE或者直接WA,全部换成int看会不会A,别动这里!!!
const int N=100007;
const ll mod=1e9+7;
const double EPS=1e-5;
  • 10
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁凡さん

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值