洛谷p1886 滑动窗口
题目链接:###
题目分析:###
单调队列经典题,话说我第一次做这个题的时候是用线段树水的
两个单调队列分别维护最小最大值,因为窗口有k的长度限制所以维护下标更方便
又由于是从左往右扫过去的,所以可以保证下标和值都是单调的
读一个维护一个,以单增队列为例,每读入一个元素就把前面比它大的都弹出,然后将元素入队
因为窗口有k长,所以i>=k的时候再开始记录答案,将已经在窗口外的元素(即i-元素下标>=k)从队头弹出队列(这时候就体现出维护下标的作用了,维护元素的话就要再开一个数组记下标),做完之后队头元素就是最小值,记录在ans1中
单减队列同理
最后输出两个数组就好了
代码:###
#include<bits/stdc++.h>
#define MAXN (1000000+5)
using namespace std;
inline int read(){
int f=1,cnt=0;char c;
c=getchar();
while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
while(isdigit(c)){cnt=cnt*10+c-'0';c=getchar();}
return cnt*f;
}
int q1[MAXN],q2[MAXN];//q1->max,q2->min
int n,k,a[MAXN];
int l1,l2,r1,r2;
int ans_min[MAXN],ans_max[MAXN];
int main(){
n=read();k=read();
for(register int i=1;i<=n;i++){
a[i]=read();
while(l1<=r1&&a[i]>=a[q1[r1]])r1--;
q1[++r1]=i;
while(l2<=r2&&a[i]<=a[q2[r2]])r2--;
q2[++r2]=i;
if(i>=k){
while(l1<=r1&&i-q1[l1]>=k)l1++;
while(l2<=r2&&i-q2[l2]>=k)l2++;
ans_max[i-k+1]=a[q1[l1]];ans_min[i-k+1]=a[q2[l2]];
}
}
for(register int i=1;i<=n-k+1;i++)printf("%d ",ans_min[i]);
printf("\n");
for(register int i=1;i<=n-k+1;i++)printf("%d ",ans_max[i]);
return 0;
}