1. 程式人生 > >單調佇列與優先佇列

單調佇列與優先佇列

單調佇列與優先佇列的區別:單調佇列的長度取決於輸入資料的合法性,而優先佇列的長度始終與輸入資料的數量等同。而他們的單調性都是單調遞減或單調遞增。

單調佇列
單調佇列例題:https://www.luogu.org/problemnew/show/P1886

#include<cstdio>
#include<iostream>
#include<cmath>
#include<deque>
using namespace std;
deque <int>win,num;//雙端佇列 win:單調佇列 num:時間戳普通佇列 
int a[1000005],n,k;
void maxx(){
	win.clear();num.clear();//先清空兩個佇列 
	for(int i=1;i<=n;i++){//遍歷所有數字 
		while(win.size()>0&&win.back()<a[i]){//如果視窗中有值(這個判斷是為了防止視窗中一開始無值的情況)並且視窗的最後一個值比目前到達的真實數字小 
			win.pop_back();num.pop_back();//由於windows是單調佇列 ,如果把a[i]直接放進去,會導致單調性錯誤
		}	//(我們要保證佇列是單調遞減佇列,也就是說最後一個值是最小的,那麼a[i必須比當前的值小,所以a[i必須不能大於佇列的最後一個值 
		win.push_back(a[i]);num.push_back(i);//上面已經保證了佇列的單調性,所以可以直接新增值 
		if(num.front()==i-k){win.pop_front();num.pop_front();}//如果時間戳剛好到了i-k,也就是到了窗戶的前面(窗戶本身是沒有厚度的,因此不需要考慮窗戶邊的情況 
		if(i>=k)cout<<win.front()<<" ";//這裡的判斷是為了防止窗戶還沒造完就開始輸出的情況 
	}
	cout<<endl;
}
void minn(){//同理。 
	win.clear();num.clear();
	for(int i=1;i<=n;++i){
		while(win.size()>0&&win.back()>a[i]){win.pop_back();num.pop_back();}
		win.push_back(a[i]);num.push_back(i);
		if(num.front()==i-k){win.pop_front();num.pop_front();}
		if(i>=k)cout<<win.front()<<" ";
	}
	cout<<endl;
}
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++)cin>>a[i];
	minn();
	maxx();
	return 0;
}

優先佇列