NKOI 2152 滑动窗口

【单调队列】滑动窗口

Time Limit:10000MS  Memory Limit:65536K
Total Submit:232 Accepted:112
Case Time Limit:1000MS

Description

给你一个长度为N(N<=10^6)的数组,一个长为K的滑动的窗体从最左移至最右端,你只能见到窗口的K个数,每次窗体向右移动一位,找出窗体所包含的数字的最大和最小值,如下表所示:k的值为3




窗口位置                      最小值   最大值



[1  3  -1] -3  5  3  6  7       -1       3 

 1 [3  -1  -3] 5  3  6  7       -3       3 

 1  3 [-1  -3  5] 3  6  7       -3       5 

 1  3  -1 [-3  5  3] 6  7       -3       5 

 1  3  -1  -3 [5  3  6] 7        3       6 

 1  3  -1  -3  5 [3  6  7]       3       7 

Input

第1行为n,k,第2行为长度为n的数组。

Output

共2行,第1行是每个位置的min value,第2行是每个位置的max value。

Sample Input

8 3
1 3 -1 -3 5 3 6 7

Sample Output

-1 -3 -3 -3 3 3
3 3 5 5 6 7

Source

poj 2823


可以构造一个递增序列和递减序列,当窗口滑动到一个新位置时,对于自增序列需要维护它的单调性,则如果新元素比队尾元素小队尾元素就出队列(因为没有存在的意义了)。然后判断队列首的元素是否还在窗口内,找到第一个在窗口内的就是满足条件的该窗口的最小数据。
对于窗口内的最大数据可以采用类似的处理方法。

以求窗口中最大值为例
此问题单调递减队列操作方法:
1.若队尾元素小于要加入的元素,
删除队尾元素,直到队尾元素不小
于新加入的元素或者队列为空
2.讨论队首元素的下标是否在窗口
范围以内,若不在,删除队首。
3.当前队首元素即是当前窗口的最大值

注意:可用二分法优化算法

假如当前入队元素为x;
   1.用二分法找出队列中比x大的第一个元素y;
   2.将队列中y以后的所有元素都从队列中删除;
   3.x入队;
注意:若找不到比x大的元素,则全部删除,然后x入队

#include<cstdio>
#include<deque>
#include<iostream>
using namespace std;
inline void _read(int &xx){
    char tt=getchar();bool asd=false;
    while((tt<'0'||tt>'9')&&tt!='-')tt=getchar();
    if(tt=='-')asd=true,tt=getchar();
    for(xx=0;tt>='0'&&tt<='9';tt=getchar())xx=xx*10+(tt-'0');
    if(asd==true)xx=0-xx;
}
struct wk{
	int num;
	int id;
};
deque<wk>bger;
deque<wk>smer;
int n,k,s[1000005];
int maxx[1000005],minn[1000005];
int cax=0,cit=0;
void push_bg(int x,int y){
	wk temp;
	temp.num=x;
	temp.id=y;
	bger.push_back(temp);
}
void push_sm(int x,int y){
	wk temp;
	temp.num=x;
	temp.id=y;
	smer.push_back(temp);
}
int main(){
	_read(n);
	_read(k);
	int i,j;
	for(i=1;i<=n;i++)_read(s[i]);
	push_bg(s[1],1);
	push_sm(s[1],1);
	for(i=2;i<=k;i++){
		while(!smer.empty()&&s[i]>=smer.back().num)smer.pop_back();
		push_sm(s[i],i);
		while(!bger.empty()&&s[i]<=bger.back().num)bger.pop_back();
		push_bg(s[i],i);
	}
	maxx[++cax]=smer.front().num;
	minn[++cit]=bger.front().num;
	for(i=k+1;i<=n;i++){
		while(!smer.empty()&&s[i]>=smer.back().num)smer.pop_back();
		push_sm(s[i],i);
		while(!bger.empty()&&s[i]<=bger.back().num)bger.pop_back();
		push_bg(s[i],i);
		while(smer.front().id<=i-k)smer.pop_front();
		maxx[++cax]=smer.front().num;
		while(bger.front().id<=i-k)bger.pop_front();
		minn[++cit]=bger.front().num;
	}
	for(i=1;i<=cit;i++)printf("%d ",minn[i]);
	printf("\n");
	for(i=1;i<=cax;i++)printf("%d ",maxx[i]);
}

你可能感兴趣的:(NKOI 2152 滑动窗口)