洛谷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;
}
posted @ 2019-01-19 13:32  kma_093  阅读(114)  评论(0编辑  收藏  举报