一、單調棧
單調棧是指乙個棧內部的元素具有嚴格單調性的一種資料結構,分為單調遞增棧和單調遞減棧。
其具有以下兩個性質:元素進棧過程:1,滿足棧底到棧頂的元素具有嚴格單調性。
2,滿足棧的先進後出特性,越靠近棧頂的元素越後出棧。
對於乙個單調遞增棧來說,若當前進棧的元素為a,如果a《棧頂元素,則直接將a進棧。
如果a≥棧頂元素,則不斷將棧頂元素出棧,直到滿足a《棧頂元素。
假設維護乙個單調上公升的棧。如果入棧元素小於棧頂那麼就要開始pop。而pop掉的元素一定全都大於這個入棧元素。單調棧內的兩個相鄰元素a,b如果在原序列中不是相鄰的,則意味著b的出現pop掉了中間的元素,因此這中間的元素必定都大於b。
乙個元素的進入彈掉了一部分元素,由此求出最左延伸量。如果乙個元素即將被pop,意味著終於出現了乙個比它小的,就可以求出最右延伸量了。
時間複雜度分析
對於每個元素,其有且僅有一次插入,最多出現一次刪除,故其時間複雜度為o(n)。
例題:hdu1506**如下:
#include
#define ll long long
#define maxn 100010
using namespace std;
int h[maxn]
,l[maxn]
,r[maxn]
;stack<
int> s;
intmain()
while
(!s.
empty()
)for
(int i=
1;i<=n;i++)if
(s.empty()
)else
s.push
(i);
}while
(!s.
empty()
)for
(int i=n;i>=
1;i--)if
(s.empty()
)else
s.push
(i);
}for
(int i=
1;i<=n;i++
) cout<
}return0;
}
二、單調佇列單調佇列與單調棧及其相似,把單調棧先進後出的性質改為先進先出既可。
元素進佇列的過程對於單調遞增佇列。
對於乙個元素a,如果a>隊尾元素,那麼直接將a扔進佇列,如果a≥隊尾元素,則將隊尾元素出佇列,直到滿足 a>隊尾元素即可。
注意:一般的佇列不支援隊尾刪除,所以一般用雙端佇列dequeue,但是用陣列模擬就不存在這樣的問題
時間複雜度分析
對於每個元素,其有且僅有一次插入,最多出現一次刪除,故其時間複雜度為o(n)。
例題:hdu 3530**如下:
#include
#define ll long long
#define maxn 200010
using namespace std;
int a[maxn]
;deque<
int> q1,q2;
intmain()
while
(!q1.
empty()
)while
(!q2.
empty()
)int flag=0;
for(
int i=
1;i<=n;i++
) q1.
push_front
(i);
while
(!q2.
empty()
&&a[i]
front()
])q2.
push_front
(i);
while
(!q1.
empty()
&&!q2.
empty()
&&a[q1.
back()
]-a[q2.
back()
]>k)
else}if
(!q1.
empty()
&&!q2.
empty()
&&a[q1.
back()
]-a[q2.
back()
]>=m)
} cout<
}return0;
}
——————後序補充中。。。。。 單調棧與單調佇列入門
特點1 top指向最後乙個數所在位置 特點2 後進先出 特點3 遞增或遞減 例題 poj2796 大意 求乙個區間,這個區間內 所有數的和sum 區間內min 的值 相比其他區間大 輸入 6 3 1 6 4 5 2 輸出 60 3 5問題 求出每個數在哪個區間內最小 區間怎麼求 將這個數 區間總值 ...
單調佇列 入門
今天寫了人生中第乙個單調佇列,激動ing 先看一道單調佇列的入門題 乙個含有n項的數列 n 2000000 求出每一項前面的第m個數到它這個區間內的最小值。先寫出動規方程 f i min j合法 很明顯的,這是乙個n 2的動規,但是,我們可以注意到,數列中有些數無論如何都不會被選到.如 1 2 8 ...
單調佇列入門
單調佇列是一種佇列 廢話 其中佇列的元素保證是單調遞增或者是單調遞減的 那麼隊首的元素不就是最小 或最大 的嗎?我們結合具體的題目來看看吧 傳送門 p1886 滑動視窗 現在有一堆數字共n個數字 n 10 6 以及乙個大小為k 的視窗。現在這個從左邊開始向右滑動,每次滑動乙個單 位,求出每次滑動後視...