學習筆記 單調佇列與單調棧

2022-09-19 09:36:07 字數 2322 閱讀 9994

乙個具有單調性的棧。插入乙個元素時,如果直接插入不滿足單調性,就一直彈出,直到插入後滿足單調為止。

luogu p1886/loj p10175

meaning of the problem

給你乙個數列 \(a\) ,多組長度為 \(k\) 的區間的最大值與最小值。

solution

一道非常經典的單調佇列題。

以最大值為例:

插入乙個數時,如果直接插入不滿足遞減,就一直彈出,直到插入後滿足遞減為止。如果隊頭存的下標超出了這個區間就彈出。最後隊頭就是最大值。

最小值思路差不多,不說了。

code

#include #define _for(i,a,b) for(int i=a;i<=b;++i)

#define for_(i,a,b) for(int i=a;i>=b;--i)

#define ll long long

using namespace std;

const int n=1e5+10,inf=0x3f3f3f3f;

int n,k,a[n],ans;

int q1[n],h1,t1,q2[n],h2,t2;

int main()

_for(i,k,n)printf("\n");

_for(i,k,n)

return 0;

}

luogu p2216/loj p10182

meaning of the problem

在乙個 \(a*b\) 的矩陣中找乙個 \(n*n\) 的矩陣,使該矩陣中最大值與最小值差最小。

solution

我們可以先用單調佇列維護出來長度為 \(n\) 的橫條最大值和最小值,再去算出矩陣的最大值和最小值。時間複雜度 \(o(abn)\) 。

code

#include #define _for(i,a,b) for(int i=a;i<=b;++i)

#define for_(i,a,b) for(int i=a;i>=b;--i)

#define ll long long

using namespace std;

const int n=1e3+10,inf=0x3f3f3f3f;

int a,b,n,ans=inf;

int mt[n][n],ax[n][n],in[n][n];

int q1[n],q2[n],h1,h2,t1,t2;

void line()

_for(j,n,b)

_for(j,n,b) }}

int main()

} printf("%d\n",ans);

return 0;

}/*5 4 2

1 2 5 6

0 17 16 0

16 17 2 1

2 10 2 1

1 2 2 2

*/

乙個具有單調性的棧。插入乙個元素時,如果直接插入不滿足單調性,就一直從後彈出,直到插入後滿足單調為止。一般用雙端佇列實現。

(stl裡有雙端佇列deque,但常數較大,建議手寫)

blocks:luogu p3503/loj p2453

題解在這裡

懶得複製了

luogu p4147

meaning of the problem

在乙個 \(n*m\) 的矩陣中找到乙個最大的矩形,求它的面積。

solution

當遍歷到第 \(i\) 行時,我們先算出它能向上延伸多少(即高度),然後把它的高度當作它所在矩陣的最低高度,用單調棧對他左右延伸,找出它所在矩形的寬度,即維護左邊第乙個比它矮的數的位置加 \(1\) 和右邊第乙個比它矮的數的位置減 \(1\) 。找出它的高度和寬度後,就可以計算出它的面積了。

code

#include #define _for(i,a,b) for(int i=a;i<=b;++i)

#define for_(i,a,b) for(int i=a;i>=b;--i)

#define ll long long

using namespace std;

const int n=1010,inf=0x3f3f3f3f;

int n,m,a[n],ml[n],mr[n],ans;char c;

struct stru;

int main()for_(j,m,1)

} printf("%d",ans*3);

return 0;

}

\[\huge\mathfrak

\]

單調佇列與單調棧

單調棧 單調棧,顧名思義,就是維持單調性 遞增或者遞減 的棧結構,如果新入棧的元素破壞了單調性,就彈出原先棧內元素,直到能夠滿足單調性 用途 它可以很方便地求出某個數的左邊或者右邊第乙個比它大或者小的元素,而且總時間複雜度o n 並且單調棧本身並不難實現 維護 每次入棧前先檢驗入棧後是否會破壞棧的單...

單調佇列與單調棧

線段樹等等容易tle,我們需要乙個o n 的演算法來解決這個問題。思路 可以看出,這個視窗是可以用乙個雙向佇列來模擬的,每當後方加入乙個數,都要從佇列尾部開始淘汰掉所有的小於它的數,保證佇列中每乙個數的後面,在視窗範圍內沒有大於等於它的數。當隊首元素不在視窗範圍時,隊首元素出隊。這樣操作後,隊內的元...

單調佇列與單調棧

線段樹等等容易tle,我們需要乙個o n 的演算法來解決這個問題。思路 可以看出,這個視窗是可以用乙個雙向佇列來模擬的,每當後方加入乙個數,都要從佇列尾部開始淘汰掉所有的小於它的數,保證佇列中每乙個數的後面,在視窗範圍內沒有大於等於它的數。當隊首元素不在視窗範圍時,隊首元素出隊。這樣操作後,隊內的元...