【单调队列】

【单调队列】

运用

求每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;
}
posted @ 2025-01-21 12:11  White_ink  阅读(4)  评论(0)    收藏  举报