单调队列【deque】 & 队列【STL】& 洛谷P1886 滑动窗口 & 洛谷P9905 [COCI 2023_2024 #1] AN2DL 【矩阵区间最大值】

队列【STL】

队列是只允许在一端进行插入操作,在另一端进行删除操作的线性表,简称“队”

队列是一种先进先出(First In First Out)的线性表

1.队列的STL用法↓

q.push(a):插入a到队列q的末尾

q.pop():删除队列q的队首元素

q.front():查询q的队首元素

q.back():查询q的队尾元素

q.size():查询q的元素个数

q.empty():查询q是否为空

2.队列例题

详见我的另一篇博文:洛谷P2058 [NOIP2016 普及组] 海港

双向队列【deque】(可用于单调队列)

单调队列是一种主要用于解决滑动窗口类问题的数据结构,主要用来解决区间最值问题

时间复杂度为 O ( n ) O\left (n \right ) O(n)

1.deque的STL用法

d.front():返回最前一个元素的引用

d.back():返回最后一个元素的引用

d.pop_back():删除尾部的元素,不返回值

d.pop_front():删除头部元素,不返回值

d.push_back(a):在队尾添加一个元素a

d.push_front(a):在队头添加一个元素a

2.例题:洛谷P1886 滑动窗口/【模板】单调队列

(1)题意解释

有一个长为 n n n 的序列 a a a,以及一个大小 k k k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值最小值

(2)题目分析

只需要用两个单调队列进行维护最小值最大值,然后再用队列进行时效性分析即可

(3)code↓
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;//定义边界
int n,k,q;//n:n个数,k:区间长度
int ans[3][maxn];//答案数组
struct Pof{
	int num,val;//编号和值
};
deque<Pof> mx;//用来求取最大值的单调队列
deque<Pof> mn;//用来求取最小值的单调队列
int main(){
	cin>>n>>k;
	Pof person;//定义一个名叫person的类
	for(int i=1;i<=n;i++){
		cin>>q;//输入这个数
		person.num=i,person.val=q;//这个数的编号为i,值为q
		while(!mx.empty()&&mx.back().val<q){//当队列mx非空且q值比mx的队尾的值小时执行,用于满足单调性
			mx.pop_back();//将队尾弹出
		}
		mx.push_back(person);//将这个类整个压入队列mx
		while(i-mx.front().num>=k) mx.pop_front();//如果现在的编号比mx队头的编号之间的差距大于k,就将队头弹出
		if(i>=k) ans[1][i-k+1]=mx.front().val;//因为只有大于了k才拥有答案,所以要在编号大于k时记录答案
		while(!mn.empty()&&mn.back().val>q){//当队列mn非空且q值比mn的队尾的值大时执行,用于满足单调性
			mn.pop_back();//将队尾弹出
		}
		mn.push_back(person);//将这个类整个压入队列mn
		while(i-k>=mn.front().num) mn.pop_front();//如果现在的编号比mn队头的编号之间的差距大于k,就将队头弹出
		if(i>=k) ans[2][i-k+1]=mn.front().val;//因为只有大于了k才拥有答案,所以要在编号大于k时记录答案
	}
	for(int i=1;i<=n-k+1;i++) cout<<ans[2][i]<<" ";//输出区间最小值答案
	cout<<endl;
	for(int i=1;i<=n-k+1;i++) cout<<ans[1][i]<<" ";//输出区间最大值答案
	return 0;
}

3.例题:洛谷P9905 [COCI 2023/2024 #1] AN2DL 【矩阵区间最大值】

详见我的另一篇博文:P9905 [COCI 2023/2024 #1] AN2DL 【矩阵区间最大值】

  • 20
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

花火Spark

鼓励,如星光,照亮我创作的前路

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

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

打赏作者

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

抵扣说明:

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

余额充值