POJ2823 Sliding Window 【單調隊列、單調棧初步】


【題目大意】

給你一個長度不超過1e6的序列,現在有一個數字k,表示長度爲k的子序列自左到右滑動時保持長度爲k。

現在要求出該長度爲k區間在滑動的過程中區間的最大值最小值。

【解題思路】

如果此題直接模擬或者利用最大值的單調性來做的話,在長度爲k的區間上無法保證次大值的正確性。

本題的正確的思路是單調隊列。

首先求出每次滑動的最小值。

我們考慮維護一個下標隊列,首先將前k的數直接加入隊列。

然後用一個指針從k+1位掃到最後一位,遇到的數如果比要插入的數大,則刪除隊尾元素,將指針前移,重複操作知道該元素遇到一個比它大的元素,或隊列爲空。

記住保存到一定是下標。

然後重複以上操作求出最大值(將條件改爲“遇到的數如果比要插入的數小”)

【代碼】

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cctype>
#include<iomanip>
#define LL long long
//#define LOCAL
using namespace std;

namespace output{
    char ch[1000];
}

const int N=1000011;
int n,m,k;
int head,tail;
int q[N];
int a[N];

inline int CIN(){
	int num=0;
	int f=1;
	char c=getchar();
	while ((c>'9'||c<'0')&&c!='-') c=getchar();
	if (c=='-'){
		f=-1;
		c=getchar();
	}
	while (c>='0'&&c<='9'){
		num=(num<<3)+(num<<1)+c-'0';
		c=getchar();
	}
	return f*num;
}

inline void COUT(int x){
	if (x==0){
		putchar(48);
		return;
	}
	if (x<0){
		putchar('-');
		x=-x;
	}
	char *s=output::ch;
	while (x){
        *(++s)=x%10;
        x/=10;
	} 
	while (s!=output::ch) putchar((*(s--))+48);
}

struct humdrum{//下標隊列 
	int q[N];
	bool exist[N];
	int zjl;
	
	void Insert_Max(int x){	
		while (tail>=head&&a[q[tail]]<=a[x]) exist[q[tail--]]=false;
		q[++tail]=x;
		exist[x]=true;
	}
	
	void Insert_Min(int x){	
		while (tail>=head&&a[q[tail]]>=a[x]) exist[q[tail--]]=false;
		q[++tail]=x;
		exist[x]=true;
	}
	
	void Delete(int x){
		if (exist[x]) head++;
	}
	
	void Clear(){
		memset(exist,false,sizeof(exist));
		memset(q,0,sizeof(q));
		zjl=0;
	}
}que;

int main(){
#ifdef LOCAL
    freopen("POJ2823.in","r",stdin);
#endif
	while (scanf("%d%d",&n,&k)!=EOF){
		que.Clear();
		head=0;
		tail=-1;
		for (int i=1;i<=n;++i) a[i]=CIN();
		
		for (int i=1;i<=k;++i) que.Insert_Min(i);
		COUT(a[que.q[head]]);
		putchar(' ');
		for (int i=k+1;i<=n;++i){
			que.Insert_Min(i);
			que.Delete(i-k);
			if (i!=n) COUT(a[que.q[head]]),putchar(' ');
			else COUT(a[que.q[head]]),putchar('\n');
		}
		
		que.Clear();
                head=0;
                tail=-1;
		for (int i=1;i<=k;++i) que.Insert_Max(i);
		COUT(a[que.q[head]]);
		putchar(' ');
		for (int i=k+1;i<=n;++i){
			que.Insert_Max(i);
			que.Delete(i-k);
			if (i!=n) COUT(a[que.q[head]]),putchar(' ');
			else COUT(a[que.q[head]]),putchar('\n');
		}
	}
	return 0;
}



【總結】

單調隊列,單調棧可以優化很多問題,務必掌握!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章