OI 單調佇列

2022-08-19 06:48:13 字數 1805 閱讀 8639

所謂單調佇列,就是乙個保持著某種性質的佇列,通常是佇列從隊頭到隊尾,維護一種遞增遞減的關係。

這種佇列通常用來解決一些連續區間的最值問題。

這種佇列的入隊要保證符合當前的性質,例如乙個遞增的單調序列(從左到右是從頭到尾):7,9,10,11

這時,入隊時要保證是遞增的:例如12這個元素可以入隊,而10這個元素不行。

這時我們看隊頭,這就是整個佇列中最小的元素。所以,遞增的佇列可以維護最小值;遞減的佇列可以維護最大值。

當然,實現乙個單調佇列需要看題目要求,通常需要對隊頭和隊尾進行更新。

例如這道題:

現在有一堆數字共n個數字(n<=10^6),以及乙個大小為k的視窗。現在這個從左邊開始向右滑動,每次滑動乙個單位,求出每次滑動後視窗中的最大值和最小值。

這道題可以使用單調佇列來做。

在滑動視窗的時候,改變只有視窗序列中的第乙個元素和最後乙個元素,所以我們可以把一開始的序列同樣的放到兩個單調佇列中,乙個遞增,乙個遞減,分別維護最小值和最大值。

用求最小值(遞增單調佇列)做例子,我們對每個元素執行這樣乙個判斷:

1.如果當前元素《隊尾,那麼刪除隊尾。不停執行該操作,直到隊為空且沒有可以刪除的隊尾為止。

2.在隊尾加上當前元素。

3.如果隊頭離開了視窗的範圍,那麼刪除隊頭。

求最大值的操作類似。

根據上題,我們可以總結出單調佇列一般有這樣的步驟:

1.如果當前元素小於或者大於(遞增或者遞減)隊尾,那麼刪除隊尾。不停執行該操作,直到隊為空且沒有可以刪除的隊尾為止。

2.在隊尾加上當前元素。

3.如果隊頭離開了題目的範圍,那麼刪除隊頭。

題目描述

乙個含有n項的數列(n<=2000000),求出每一項前的m個數到它這個區間內的最小值。若前面的數不足m項則從第1個數開始,若前面沒有數則輸出0。

這道題依然用單調佇列做。注意,這道題的區間指的是每一項的前m個數,不包括這一項。

所以,我們維護乙個遞增的單調佇列,長度最長為m,步驟類似上文所講。

**:

#include#include

#include

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long

ll;const ll inf=99999999

;const

int maxn = 2000010

;int

a[maxn];

int que[maxn][2

];int n,m,head = 1

,tail;

intmain()

printf(

"0\n");

que[++tail][0] = a[1

]; que[tail][

1] = 1

;

for(int i = 2; i <= n; i++)

que[++tail][0] = a[i-1

]; que[tail][

1] = i-1

;

while(head <= tail &&que[head][1] < i-m)

head++;

printf(

"%d\n

",que[head][0

]); }

return0;

}

p1440

單調棧,單調佇列

大多數借鑑了 單調佇列是什麼呢?可以直接從問題開始來展開。poj 2823 給定乙個數列,從左至右輸出每個長度為m的數列段內的最小數和最大數。數列長度 n 106,m n 我們知道,解法 在暴力列舉的過程中,有乙個地方是重複比較了,就是在找當前的f i 的時候,i的前面其它m 1個數在算f i 1 ...

單調棧 單調佇列

單調棧 單調佇列是在棧和佇列的基礎上加上單調結構的資料結構。如果乙個元素入棧或入隊,他會檢查之前的元素,如果之前的元素不可能是答案的解,那麼就彈出元素,使得當前元素入棧或入隊。leetcode 239 滑動視窗最大值 此題是單調佇列,每次遇到乙個元素,一直從隊尾彈出,直到隊尾元素大於該元素為止。還需...

單調棧 單調佇列

啊學完了來寫個總結吧 顧名思義,單調,就是指色彩單一某乙個容器裡面的元素都是遞增或遞減的,而單調棧和單調佇列就是這個容器。單調棧 單調棧模板 其他的我就不說了,講下為什麼單調棧是從後往前掃瞄 當我們在判斷乙個數後面第乙個比它大的數時,前提是後面的數已經被處理了,所以我們要從後往前掃瞄。我做了兩種做法...