单调队列
可以用来找i——i+k中这个区间的最大值或者最小值。
实现方式和单调栈类似
用一个双向队列来实现 deque q;
对列里一些点的位置
用一个数组ml[i] 来记录i - i-k之间的最小值的位置
那应该怎么维护呢?就和单调栈很类似
for(int i=1;i<=n;i++){
while(q.size()&&(i-q.front()+1)>k){
q.pop_front();
}
while(q.size()&&a[i]<=a[q.back()]){
q.pop_back();
}
if(q.size()==0){
ml[i] = i;
}else{
ml[i] = q.front();
}
q.push_back(i);
}
第一个while 是为了维护一个单调递增的队列,这样最前面的那个才能是我们的最小值的位置
第二个while 是为了保证我们要的区间长度不能超过k
单调队列的裸题 用来存以下模板
洛谷P1886
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
deque<int> q;
int a[maxn];
int ml[maxn];//左边的符合条件的最小值的下标
int mm[maxn];//左边的符合条件的最大值的下表
int n,k;
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++){
while(q.size()&&(i-q.front()+1)>k){
q.pop_front();
}
while(q.size()&&a[i]<=a[q.back()]){
q.pop_back();
}
if(q.size()==0){
ml[i] = i;
}else{
ml[i] = q.front();
}
q.push_back(i);
}
while(q.size()) q.pop_back();
for(int i=1;i<=n;i++){
while(q.size()&&(i-q.front()+1)>k){
q.pop_front();
}
while(q.size()&&a[i]>=a[q.back()]){
q.pop_back();
}
if(q.size()==0){
mm[i] = i;
}else{
mm[i] = q.front();
}
q.push_back(i);
}
for(int i=k;i<=n;i++){
cout<<a[ml[i]];
if(i==n) cout<<endl;
else cout<<" ";
}
for(int i=k;i<=n;i++){
cout<<a[mm[i]];
if(i==n) cout<<endl;
else cout<<" ";
}
return 0;
}