1. 程式人生 > >【模擬試題】滑動視窗(BSOI2604)

【模擬試題】滑動視窗(BSOI2604)

【模擬試題】滑動視窗

Description

  給你一個長度為N的陣列,一個長為K的滑動的窗體從最左移至最右端,你只能見到視窗的K個數,每次窗體向右移動一位,如下圖:
      
  你的任務是找出窗體在各位置時的最大值和最小值。

Input

  第1行:2個整數N,K(K<=N<=1000000) 
  第2行:N個整數,表示陣列的N個元素(<=2*10^9) 

Output

  第1行:滑動視窗從左向右移動每個位置的最小值,每個數之間用一個空格分開 
  第2行:滑動視窗從左向右移動每個位置的最大值,每個數之間用一個空格分開

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

Solution

單調佇列模板。

維護一個長度為k的單調佇列,每次用隊首來的出最大和最小值,新加入的數就放在隊尾。

如果隊首的距離大於k,則head++,即隊首出隊。若新來的數值比隊尾更優,則tail--,即隊尾出隊。

CODE

#include<iostream>
#include<cstdio>
using namespace std;
int n,k,a[1000005];
struct Queue{int val,pos;}q[1000005];
inline int read(){
	char c;int rec=0,f=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')f=-1;
	while(c>='0'&&c<='9')rec=rec*10+c-'0',c=getchar();
	return rec*f;
}
void work(bool f) {
	int head=1,tail=0,i;
	for(i=1;i<k;i++) {
		if(f)while(a[i]<q[tail].val&&tail>0)tail--;
		else while(a[i]>q[tail].val&&tail>0)tail--;
		q[++tail].val=a[i];q[tail].pos=i;
	}
	for(i=k; i<=n; i++) {
		if(f)while(a[i]<q[tail].val&&tail>=head)tail--;
		else while(a[i]>q[tail].val&&head<=tail)tail--;
		q[++tail].val=a[i];q[tail].pos=i;
		while(q[head].pos+k<=i&&head<=tail)head++;
	    cout<<q[head].val<<" ";
	}cout<<'\n';
	return ;
}
int main() {
	n=read();k=read();
	for(int i=1;i<=n;i++)a[i]=read();
	work(1);work(0);
	return 0;
}