P1886 AC但有个地方有点不太懂(求助)

P1886 滑动窗口 /【模板】单调队列

MoYi__666 @ 2023-09-01 21:56:26

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<bits/stdc++.h>

using namespace std;

#define itn int
#define ll long long
#define ull unsigned long long
#define ff()  for(int i=1;i<=n;i++)

const int maxn=91451451;

deque<int> q;

int n , m , num;
int a[maxn];
int b[maxn];

inline int read(){//神奇的读优
    int h_=1,d_=0;char t_=getchar();
    while(t_<'0' || t_>'9'){if(t_=='-')h_=-1;t_=getchar();}
    while(t_>='0' && t_<='9'){d_=d_*10+t_-'0';t_=getchar();}return h_*d_;
}
void print(int x_){//快输
    if(x_<0){
        putchar('-'),x_=-x_;
    }
    if(x_>9){
        print(x_/10);
    }
    putchar(x_%10+'0');
    return ;
}

signed main(){
    n = read();
    m = read();
    ff()
    {
        cin >> a[i];
    }
    for (int i = 1;i <= n; i++)//min
    {
        while (!q.empty() && a[q.back()] > a[i])
        {
            q.pop_back();
        }
        q.push_back(i);
        if (i >= m )
        {
            while(!q.empty()&&q.front()<=i-m) q.pop_front();
            cout<<a[q.front()]<< ' ';
        }

    }
    cout<<'\n';
    while(!q.empty())q.pop_front();
    for (int i = 1;i <= n; i++)//max
    {
        while (!q.empty() && a[q.back()] < a[i])
        {
            q.pop_back();
        }
        q.push_back(i);
        if (i >= m )
        {
            while(!q.empty()&&q.front()<=i-m) q.pop_front();
            cout<<a[q.front()]<<' ';
        }

    }
    cout<<'\n';
    return 0;
}

那几个while循环都有点懵逼,请大佬解答一下是什么个原理

万分感谢~~~


by Q__A__Q @ 2023-09-01 22:17:05

@MoYi__666 以求区间最大值为例: 如果这个数不在窗口内就弹出,从队头开始判断: if(q[head]<i-m) head++

如果前一个数(在队列中)比准备入队的数小,那么前面的这个数弹出。因为前面这个数必定比准备入队的数先出队并且最大值一定不在这个数取到,所以可以舍去:while(head<=tail&&a[q[tail]<a[i]) tail--


by MoYi__666 @ 2023-09-03 16:58:36

thx


|