【洛谷P1886】滑动窗口【单调队列】
题目描述
有一个长为 nn 的序列 aa,以及一个大小为 kk 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。
例如:
The array is [1,3,-1,-3,5,3,6,7][1,3,−1,−3,5,3,6,7], and k = 3k=3。
输入格式
输入一共有两行,第一行有两个正整数 n,kn,k。 第二行 nn 个整数,表示序列 aa
输出格式
输出共两行,第一行为每次窗口滑动的最小值
第二行为每次窗口滑动的最大值
输入
8 3
1 3 -1 -3 5 3 6 7
输出
-1 -3 -3 -3 3 3
3 3 5 5 6 7
开始一直把优先队列和单调队列混淆,学习完单调队列才发现两者并不一样。
单调队列是维护一个递增或递减的序列。以题目输出k区间的最小值为例,q是被维护的deque:
1.输入1,q[1];
2.输入3,3有可能是别的区间的最小值,q[1,3];
3,输入-1,因为队尾是3,而3>-1,有-1的存在3就不可能是某个区间的最小值,所以抛出3,同理抛出1,q[-1],输出-1;
4.输入-3,-1>-3抛出-1,输出-3;
5.输入5,q[-3,5],输出-3;
6.输入3,3>5,抛出5,q[-3,3],输出-3;
7.输入6,-3不在k区间内了,抛出-3,q[3,6],输出3;
8.输入7,q[3,6,7],输出3。
#include<cstdio>
#include<deque>
using namespace std;
const int N=1e6+10;
int a[N],a1[N],a2[N];
deque<int>q1;
deque<int>q2;
int main()
{
int n,k,i,j;
scanf("%d %d",&n,&k);
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
while(q1.size()&&a[q1.back()]>a[i]) q1.pop_back();
while(q2.size()&&a[q2.back()]<a[i]) q2.pop_back();
q1.push_back(i);
q2.push_back(i);
if(i>=k){
while(i-k>=q1.front()) q1.pop_front();
while(i-k>=q2.front()) q2.pop_front();
a1[i]=a[q1.front()];
a2[i]=a[q2.front()];
}
}
for(i=k;i<=n;i++)
printf("%d ",a1[i]);
printf("\n");
for(i=k;i<=n;i++)
printf("%d ",a2[i]);
printf("\n");
return 0;
}