单调队列 洛谷P1886 滑动窗口

题目链接: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;
 }
原文地址:https://www.cnblogs.com/qingjiuling/p/11336194.html