题目链接: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;
}