單調隊列模板【附例題】

其實單調隊列就是一種隊列內的元素有單調性的隊列,由於其單調性因此常常會被用來維護區間最值或者下降DP的維數已達到降維來減小空間及時間的目的。c++

每個答案只與當前下標的前m個有關,因此能夠用單調隊列維護前m的個最小值,數組

考慮如何實現該維護的過程??優化

顯然當前下標\(X\)\(m\)個之前的元素(即下標小於\(X-M+1\)的元素)確定對答案沒有貢獻,因此能夠將其從單調隊列中刪除。spa

對於兩個元素\(A\)\(B\),下標分別爲\(a\),\(b\),若是有\(A>=B\)&&\(a<b\)那麼B留在隊列裏確定優於\(A\),所以能夠將\(A\)刪除。調試

維護隊首:若是隊首已是當前元素的\(m\)個以前,將\(head\)++,彈出隊首元素code

維護隊尾:比較\(q[tail]\)與當前元素的大小,若當前元素更優\(tail\)++,彈出隊尾元素,直到能夠知足隊列單調性後加入當前元素。隊列

考慮單調隊列的時間複雜度:因爲每個元素只會進隊和出隊一次,因此爲\(O(n)\)get

P1440 求m區間內的最小值it

P1886 滑動窗口 /【模板】單調隊列模板

P3088[USACO13NOV]Crowded Cows S

#include <bits/stdc++.h>
using namespace std;
int a[2000100];
bool b[2000100];
int q[2000100];//數組模擬隊列,更好調試
int head=1,tail=0;
int n,m;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=n;i++)
	{
		while(i-q[head]+1>m&&head<=tail)//若頭結點在範圍外 
		{
			head++;//彈出頭結點 
		}
		while(a[i]<a[q[tail]]&&head<=tail)//若當前節點優於尾節點 
		{
			tail--;//彈出尾結點 
		}
		q[++tail]=i;//當前節點入隊 
	}
	return 0;
}

利用單調隊列,能夠優化涉及定長連續子區間求最值的線性dp問題

例題

P1725 琪露諾 琪露諾是最強的!!

P1714 切蛋糕

相關文章
相關標籤/搜索