【单调队列】
【单调队列】
运用
求每k个连续的数中的最大值/最小值
模版
滑动窗口https://www.acwing.com/file_system/file/content/whole/index/content/3705/
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int q[N],hh=0,tt=-1,a[N];
int n,k;
int main(){
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
//最小值
for(int i=0;i<n;i++){
//超出窗口的出队
while(hh<=tt && i-k+1>q[hh]) hh++;
//不满足单调性质的出队
while(hh<=tt && a[i]<a[q[tt]]) tt--;
q[++tt]=i;
if(i>=k-1) printf("%d ",a[q[hh]]);
}
printf("\n");
hh=0;
tt=-1;
//最大值
for(int i=0;i<n;i++){
//超出窗口的出队
while(hh<=tt && i-k+1>q[hh]) hh++;
//不满足单调性质的出队
while(hh<=tt && a[i]>a[q[tt]]) tt--;
q[++tt]=i;
if(i>=k-1) printf("%d ",a[q[hh]]);
}
return 0;
}
【题目整理】
最大子序和
https://www.acwing.com/file_system/file/content/whole/index/content/3686/
//单调队列模板题
/*思路:
(1)前缀和初始化 问题简化为s[r]-s[l-1]
(2)遍历枚举r 求s[l-1]最小值→维护单调队列
*/
#include<bits/stdc++.h>
using namespace std;
const int N=300010;
long long q[N],ans=INT_MIN;
int a[N];//维护的l队列
int n,m;
int main(){
cin>>n>>m;
//求前缀和
for(int i=1;i<=n;i++){
cin>>q[i];
q[i]+=q[i-1];
}
int hh=0,tt=0;//hh队头 ll队尾
for(int i=1;i<=n;i++){
while(hh<=tt && i-a[hh]>m) hh++;//检查出不出界:m可取 m+1不可取
ans=max(ans,q[i]-q[a[hh]]);//此时队头为最小
while(hh<=tt && q[a[tt]]>=q[i]) tt--;//入下一个队:保持单调性
a[++tt]=i;//队列一定不会为空 至少长度为1
}
cout<<ans;
return 0;
}