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; }