洛谷 P1886 滑动窗口(单调队列)
原题
本题是一道很经典的单调队列模板题,如果想要O(1)的时间内回答每个窗口,用ST表也可以,但是这道题洛谷上会被卡MLE,所以就来介绍一下单调队列。
因为是初次尝试,也为了便于理解,所以用数组模拟了单调队列
AC代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,a[1000005],p[1000005];
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
int head=1,tail=0;//定义单调队列的头指针和尾指针,储存的是数组下标。
for(int i=1;i<=n;i++)//我们先求最小值,头指针储存最小值下标
{
if(head<=tail&&p[head]<i-k+1)//首先我们要先判断队列内的元素在不在滑动窗口内,如果不在,则头指针++
head++;
while(head<=tail&&a[p[tail]]>a[i])//如果比队尾元素小的话,就继续往下寻找(tail++),直到找不到
tail--;
p[++tail]=i;//加入队尾
if(i>=k)//保证滑动窗口合法
printf("%d ",a[p[head]]);
}
puts("");
head=1,tail=0;
for(int i=1;i<=n;i++)
{
while(head<=tail&&p[head]<i-k+1)
head++;
while(head<=tail&&a[p[tail]]<a[i])//找最大值同理,只要改变下进入队列的比较符号即可
tail--;
p[++tail]=i;
if(i>=k)
printf("%d ",a[p[head]]);
}
return 0;
}
戒骄戒躁,百炼成钢!