POJ - 2823 Sliding Window 【单调队列基础】

ZJM 有一个长度为 n 的数列和一个大小为 k 的窗口, 窗口可以在数列上来回移动. 现在 ZJM 想知道在窗口从左往右滑的时候,每次窗口内数的最大值和最小值分别是多少. 例如:
数列是 [1 3 -1 -3 5 3 6 7], 其中 k 等于 3.

思路:板子题,输出的时候分两行分别输出区间最小值和最大值

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include <sstream>
#include<vector>
#include<cmath>    
#include<stack>
using namespace std;
#define io ios::sync_with_stdio(0),cin.tie(0)
#define ms(arr) memset(arr,0,sizeof(arr))
#define LD long double
#define LL long long
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define inf 1<<30
#define  ull unsigned long long
const int Mod = 998244353;
const int maxn = 1e7 + 9;
int read()
{
    int x = 0, f = 1; char ch = getchar();
    while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
struct node
{
    int x;
    int step;
};
int a[maxn];
node Max[maxn];
node Min[maxn];
int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k)){
        for(int i=1;i<=n;i++){
            a[i]=read();
        }
        if(k==1){//区间为1则直接输出即可
            for(int i=1;i<=n;i++){
                if(i!=1)
                    printf(" ");
                printf("%d",a[i]);
            }
            printf("\n");
            for(int i=1;i<=n;i++){
                if(i!=1)
                    printf(" ");
                printf("%d",a[i]);
            }
            printf("\n");
            continue;
        }
        int head,tail;
        //先算区间最小的
        head=tail=1;
        Min[1].x=a[1];
        Min[1].step=1;
        for(int i=2;i<=n;i++){
            while(head<=tail&&Min[tail].x>a[i])tail--;//把队列中比a[i]大的删除,直到队列中所有数都比a[i]小
            Min[++tail].x=a[i];//把a[i]插入
            Min[tail].step=i;//记录位置
            while(i-Min[head].step+1>k)head++;//如果队头已经不在当前k的范围中就删除
            if(i>=k){
                if(i!=k)printf(" ");
                printf("%d",Min[head].x);//输出最小值
            }    
        }
        printf("\n");
        //后算区间最大的
        head=tail=1;
        Max[1].x=a[1];
        Max[1].step=1;
        for(int i=2;i<=n;i++){
            while(head<=tail&&Max[tail].x<a[i])tail--;//把队列中比a[i]小的删除,直到队列中所有数都比a[i]大
            Max[++tail].x=a[i];//把a[i]插入
            Max[tail].step=i;//记录位置
            while(i-Max[head].step+1>k)head++;//如果队头已经不在当前k的范围中就删除
            if(i>=k){
                if(i!=k)printf(" ");
                printf("%d",Max[head].x);//输出最大值
            }            
        }
        printf("\n");
    }
    return 0;
}

 

posted @ 2021-03-21 20:52  夜灯长明  阅读(47)  评论(0编辑  收藏  举报