题目链接:https://www.luogu.org/problem/P1886
题意:给一串一维数字序列,并给你一个长为k的小框,从左到右一格格滑过去,求每次小框内的最大值最小值分别为多少。
据说是单调队列模板题。讲解洛谷排第一的题解就讲的很好。
简略说就是维护一个单调的队列(增或减)每次移到新的一格就会把队尾和当前做比较,不满足单调性就一直去掉队尾,一直到满足为止,因为有单调性,队首就是答案。除了队列q数组,还有一个p数组,用来放队内元素在原序列中的下标。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf=1<<30; const int maxn=1e6+7; int a[maxn],p[maxn],q[maxn]; int n,k; void ask_min(){ memset(p,0,sizeof(p)); memset(q,0,sizeof(q)); int tail=1,head=0; for(int i=1;i<=n;i++){ while(head<=tail&&q[tail]>=a[i])tail--; q[++tail]=a[i];p[tail]=i; while(p[head]<=i-k)head++; if(i>=k)printf("%d ",q[head]); } } void ask_max(){ memset(p,0,sizeof(p)); memset(q,0,sizeof(q)); int tail=1,head=0; for(int i=1;i<=n;i++){ while(head<=tail&&q[tail]<=a[i])tail--; q[++tail]=a[i];p[tail]=i; while(p[head]<=i-k)head++; if(i>=k)printf("%d ",q[head]); } } int main(){ cin>>n>>k; for(int i=1;i<=n;i++)scanf("%d",&a[i]); ask_min();cout<<endl; ask_max();cout<<endl; return 0; }