[算法学习笔记] 单调队列
当一个选手比你小还比你强,你就可以退役了。
-----单调队列
简介
单调队列一般用于维护动态区间内的极值,它可以做到线性的复杂度下求出所有动态区间的极值。
它的原理在上文引用部分已经提到,每次队列中只维护可能成为区间极值的元素,具体地,例如求区间最小值,若队列中有的数比新增加的数大,则可以直接弹出,因为它不可能成为现在乃至以后的区间最大值。新增的数一定要入队,因为显然它可能成为后面的区间极值(因为在队头会不断弹出)
单调队列一般用双端队列实现,在队头进行“退役”也就是超出滑动区间范围的数的弹出,在队尾进行不可能成为区间极值的数弹出以及新增数。
另外,由于我们每次比新增数大/小的数会弹出,所以队列元素满足单调性,因此输出的时候输出队头即可。
单调队列一般不会单独考察,主要用于优化,例如单调队列优化dp。
单调队列基本内容就这些?是不是很简单!
例题&参考板子
我的板子:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <deque>
#define N 1000010
using namespace std;
deque <int> q,q1;
int n,k;
int a[N];
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++)
{
if(!q1.empty()&&i-q1.front() >= k) q1.pop_front(); //如果队尾下标-队头下标也就是队列长度超出,则队头元素“退役”
while(!q1.empty()&&a[q1.back()] > a[i]) //弹出不可能是区间极值的元素
{
q1.pop_back();
}
q1.push_back(i); //新增元素入队尾
if(i>=k) cout<<a[q1.front()]<<" "; //动态输出队头,因为满足单调性,队列元素单调
}
cout<<endl;
for(int i=1;i<=n;i++)
{
if(!q.empty()&&i-q.front() >= k) q.pop_front();
while(!q.empty()&&a[q.back()] < a[i])
{
q.pop_back();
}
q.push_back(i);
if(i>=k) cout<<a[q.front()]<<" ";
}
}
本文作者:SXqwq,转载请注明原文链接:https://www.cnblogs.com/SXqwq/p/17615749.html