单调队列介绍
单调队列是一个较为基础的算法思想,在c++的容器中,deque可以很好的来使用单调队列算法。
具体使用
使用单调队列解决问题,主要是用单调队列的“窗口,删头,去尾”。在必要时可以使用前缀和结合使用。
首先,单调队列一般(以递增队列为例)具有以下特征:
-
队头元素始终是队列中最小的。
-
元素只从队尾进入。
-
序列中的每个元素都必须进入队列。
例如,当序列中的x进入队列时,先和队尾元素比较,若队尾元素小于x,则弹出队尾元素,直到队尾没有比x小的元素,x进入。
去尾
❌❌❌
![](https://i-blog.csdnimg.cn/blog_migrate/9d74efe708abacf835e3bbca5278cc9a.png)
此时,标号为3的元素是队尾元素,他的高度大于x,所以将其弹出。
❌❌❌
![](https://i-blog.csdnimg.cn/blog_migrate/afb9fb8651fbbaa2e7c0f9a540a03861.png)
此时标号为2的元素的高度仍然大于x,所以将其弹出。
✔️✔️✔️
![](https://i-blog.csdnimg.cn/blog_migrate/2d1a69f9f6e498f8a67ca7c5b624b127.png)
此时标号为1的元素为队尾元素,它的高度小于x,所以此时x入队。
删头
因为单调队列一直前进,若队头元素与当前元素相距太宽,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/579aa4069089f6dea0f002b6d5a6dca8.png)
此时,1是队头,4是队尾,如果题目中要求一个不大于一个数的长度的序列,就会超出窗口,所以应将1去除队列,2作为新的队头。
deque介绍
deque可以快捷的使用单调队列,其基本操作如下:
deque<type> d;
int x=1;
d.front();//返回队列中第一个元素
d.back();//返回队尾元素
d.pop_front();//去除第一个元素
d.pop_back();//去除队尾元素
d.push_back(1);//从队尾添加元素
d.push_front(1);//从队头添加元素
例题:
洛谷P1886
题解如下:
#include<iostream>
#include<deque>
using namespace std;
const int N=1000005;
int a[N];
deque <int> q;
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
while(!q.empty()&&a[q.back()]>a[i]) q.pop_back();
q.push_back(i);
if(i>=m){
while(!q.empty()&&q.front()<=i-m) q.pop_front();
cout<<a[q.front()];
}
}
cout<<endl;
while(!q.empty()) q.pop_front();
for(int i=1;i<=n;i++){
while(!q.empty())q.pop_front();
while(!q.empty()&&a[q.back()]<a[i]) q.pop_back();
q.push_back(i);
if(i>=m){
while(!q.empty()&&q.front()<=i-m) q.pop_front();
cout<<a[q.front()];
}
}
cout<<endl;
return 0;
}