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

· · 个人记录

题目描述

有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。

例如:

The array is [1,3,-1,-3,5,3,6,7] , and k = 3。

输入格式

输入一共有两行,第一行有两个正整数 n,k。 第二行 n 个整数,表示序列 a

输出格式

输出共两行,第一行为每次窗口滑动的最小值 第二行为每次窗口滑动的最大值

输入输出样例

输入#1

8 3
1 3 -1 -3 5 3 6 7

输出#1

-1 -3 -3 -3 3 3
3 3 5 5 6 7

理解与题解

#include<bits/stdc++.h>
using namespace std;
int n,m,a[1000001],maxx[1000001],minn[1000001],li=1,la=1,ra=1,ri=1,ma[1000001],mi[1000001];
int main()
{
    scanf("%d%d",&n,&m);//输入有多少个数与求最大值最小值的范围 
    for(int i=1;i<=n;i++)//li代表求最小值队列的最左,ri代表最右 
    {//la代表求最小值队列的最左,ra代表最右 
        if(li<ri&&mi[li]<=i-m)li++; //因为我们求的是在范围内的最大或最小值 
        if(la<ra&&ma[la]<=i-m)la++;//所以当我们求得的最大或最小值已经不能在现在所求范围内使用时,就要踢出 
        scanf("%d",&a[i]);//ma与mi分别代表求最大最小值的队列 
        while(la<ra&&a[ma[ra-1]]<a[i])ra--;ra++;//当发现被读入进来的值比现在队列中最后的值大时,就将它踢出 
        ma[ra-1]=i;//踢到不在比最后值大时将它读入 
        while(li<ri&&a[mi[ri-1]]>a[i])ri--;ri++;//同最大值 
        mi[ri-1]=i;//最小值就是看读入值是否比现在队列中最后一个小 
        maxx[i]=a[ma[la]];//因为我们的队列是将最大或最小的值放在最前 
        minn[i]=a[mi[li]];//当维护完时,就将答案提交 
    }
    for(int i=m;i<=n;i++)
    printf("%d ",minn[i]);
    printf("\n");
    for(int i=m;i<=n;i++)
    printf("%d ",maxx[i]);//输出 
    return 0;
}