单调队列
__Green_tick__ · · 算法·理论
单调队列
引入
在学习单调队列前,让我们先来看一道例题。
P1886 滑动窗口 /【模板】单调队列题目大意
本题大意是给出一个长度为
n 的数组,编程输出每k 个连续的数中的最大值和最小值。
暴力解法
最暴力的想法很简单,对于每一段
很显然,这其中进行了大量重复工作,除了开头
这时所用到的就是单调队列了。
定义
顾名思义,单调队列的重点分为「单调」和「队列」。
- 单调:很好理解,即队列内元素有序。
- 队列:元素只能从队头和队尾进行操作。
作用
求解关于一个区间内的极值问题。
回归问题
样例输入如下:
8 3
1 3 -1 -3 5 3 6 7
因为我们始终要维护队列保证其 递增 的特点,所以在
| 操作 | 队列状态 |
|---|---|
我们已经熟悉了单调队列的写法,尝试通过本题。
参考程序
#include<bits/stdc++.h>
using namespace std;
#define var long long
#define ln "\n"
template<typename... Args>
void print(Args... args){
return;
}
template<typename T,typename... Args>
void print(T first,Args... args){
cerr<<first<<" ";
print(args...);
return;
}
template<typename... Args>
void debug(Args... args){
cerr<<"----------------------------------"<<ln;
cerr<<"Debug :"<<ln;
print(args...);
cerr<<ln<<"Time : "<<clock()<<ln;
cerr<<"----------------------------------"<<ln;
return;
}
const var N=1e6+10;
var x;
deque<pair<var,var>> Q;
deque<pair<var,var>> R;
var maxx[N],minn[N];
var n,m,k,sum=1;
pair<var,var> lin;
int main(){
ios::sync_with_stdio();
cin.tie();
cout.tie();
cin>>n>>k;
for(var i=1;i<=n;i++){
cin>>x
lin.first=i;
lin.second=x;
while(!Q.empty() && x>Q.back().second) Q.pop_back();
while(!R.empty() && x<R.back().second) R.pop_back();
Q.push_back(lin);
R.push_back(lin);
while(i-k>=Q.front().first) Q.pop_front();
while(i-k>=R.front().first) R.pop_front();
if(i>=k){
maxx[sum]=Q.front().second;
minn[sum]=R.front().second;
sum++;
}
}
for(var i=1;i<sum;i++){
cout<<minn[i]<<" ";
}
cout<<ln;
for(var i=1;i<sum;i++){
cout<<maxx[i]<<" ";
}
cout<<ln;
return 0;
}
例题讲解
P2698 [USACO12MAR] Flowerpot S
题目大意
老板需要你帮忙浇花。给出
每滴水以每秒
我们认为,只要水滴落到
如何求解
首先:
- 所在的区间端点一定在水滴上。
暴力的解法:时间复杂度
因为在右端点右移时,花费时间只增不减,于是我们想到了双指针,时间复杂度
思路明朗,动手实践!
参考代码
#include<bits/stdc++.h>
using namespace std;
#define var long long
#define ln "\n"
template<typename... Args>
void print(Args... args){
return;
}
template<typename T,typename... Args>
void print(T first,Args... args){
cerr<<first<<" ";
print(args...);
return;
}
template<typename... Args>
void debug(Args... args){
cerr<<"----------------------------------"<<ln;
cerr<<"Debug :"<<ln;
print(args...);
cerr<<ln<<"Time : "<<clock()<<ln;
cerr<<"----------------------------------"<<ln;
return;
}
const var MaxN=1e5+10;
var n,k;
pair<var,var> arr[MaxN];
deque<var> que_max;
deque<var> que_min;
var ans=LONG_LONG_MAX;
int main(){
ios::sync_with_stdio();
cin.tie();
cout.tie();
cin>>n>>k;
for(var i=1;i<=n;i++){
cin>>arr[i].first>>arr[i].second;
}
sort(arr+1,arr+1+n);
que_max.push_back(1);
que_min.push_back(1);
var r=1;
for(var l=1;l<=n;l++){
while(que_max.size() && que_max.front()<l) que_max.pop_front();
while(que_min.size() && que_min.front()<l) que_min.pop_front();
while(r<n && arr[que_max.front()].second-arr[que_min.front()].second<k){
r++;
while(que_max.size() && arr[que_max.back()].second<=arr[r].second) que_max.pop_back();
que_max.push_back(r);
while(que_min.size() && arr[que_min.back()].second>=arr[r].second) que_min.pop_back();
que_min.push_back(r);
}
if(arr[que_max.front()].second-arr[que_min.front()].second>=k){
ans=min(ans,arr[r].first-arr[l].first);
}else{
break;
}
}
if(ans==LONG_LONG_MAX){
cout<<"-1"<<ln;
}else{
cout<<ans<<ln;
}
return 0;
}