单调栈 or 单调队列,是指序列中的元素严格递增 or 递减。可以解决一些区间上基于比较的一些题目,下面用一些经典的题目中来具体讨论.
单调栈 应用:求以某个值为下界(上界)的最大区间
RQNOJ 460 诺诺的队列
题意:有一个N个数的序列,求出所有的数对数(x,y)---x,y相邻或者它们之间没有比它们大的数.
分析:x,y两个数只算一次,所以我们不妨只按右边考虑,即对于任意一个数,我们只考虑它左边的数和它的配对.我们维护一个严格单调递减的序列,每次插入新数p时:①如果p小于栈顶元素,则把它入栈,并且res+1,因为它只可能和左边相邻的数组合;②如果p大于栈顶元素,则栈中小于p的那些数不可能和p后面的数组合了,所以完全可以把它们出栈扔掉,再把p入栈。
并且由栈的单调递减性可知这些数都可以和p组成数对,所以出栈时也要res+;③我们还需要考虑等于的情况,此时我们既不能让什么元素出栈也不能直接入栈而破坏栈的严格单调性,我的方法是把连续相等的数合并,记录下实际个数,然后在栈中当一个数处理(详细看代码吧)。
代码:
http://codepad.org/PIfSUo6W
POJ 3250 Bad Hair Day (经典模型)
求某个数右边比该数小的连续最大区间。会了上面那个题这个也就好分析了。(这题中我用栈存的数的位置而不是数。)
由于每头牛看右边,所以我们倒着入栈(其实好像不必= =……)维护一个单调递减的栈。如果待入栈数数小于等于栈顶元素,则他一个也看不到,并且直接入栈(等于时需要更新栈顶元素位置,以便后面统计栈中比待入栈数小的个数);如果大于栈顶元素,则不断弹出栈内元素直到不再大于或栈空,则这两个位置中间的牛都能看见。
代码:
http://www.shaidaima.com/source/view/11239
(这题代码有点儿不对……一个是那句S.top() = i写错了,另一个是==的情况应该放到下面那种情况(参照其他题的程序中那样) )
POJ 2559 Largest Rectangle in a Histogram (经典模型)
求最大矩形面积。(参考朱晨光论文《基本数据结构在信息学竞赛中的应用》中的方法)
根据论文中的理论,我们可以把矩形的面积当作一个竖线从左往右扫描得到。那么对于图中出现的每一个可能的竖线,只要知道它向左能扩展几个(left[i])、向右能扩展几个(right[i])就能算出这个竖线下的矩形面积了。
我们维护一个单调递增的栈,这样可以在入栈时计算left而在出栈时计算right:
①如果待入栈元素大于栈顶元素,则这条竖线不能再往左扩展,left即为当前栈顶元素位置;
②如果相等,则更新一下位置即可,不用再插入。(两个相连的同高度的竖线可以算成一个,更新位置是为了后面的元素可以找到正确的left位置)
③如果小于,left不能马上确定,但此时我们可以弹出栈内元素了---对于栈内大于该元素的元素,它们的left是已知的,而他们的right显然就是把它们弹出的元素:右边第一个比它们小的元素,所以在弹出栈内元素时就可以计算它们能扩展的面积了。最后再把待入栈元素更新left并入栈。
这样,所有的元素都会入栈、出栈,则所有可能的结果都计算出来了,求个max即可。
代码:
http://www.shaidaima.com/source/view/11240
POJ 3494 Largest Submatrix of All 1’s (
经典模型 --- 求01矩阵中最大的全1矩形)
具体解法朱晨光论文《基本数据结构在信息学竞赛中的应用》已经讲的很清楚了,就是上面POJ 2559经典模型的二维扩展~~~
代码:
http://www.shaidaima.com/source/view/11241
POJ 2082 Terrible Sets
题目神描述- -……其实就是POJ2559……当然这道题的每个矩形都有宽度,再维护一个宽度的前缀和即可。
POJ 2796 Feel Good
以某个值为下界的最大区间求和------我们每次找到一个数,用单调栈求以它做乘数(即区间最小数)左右能扩展的区间。
代码:
http://www.shaidaima.com/source/view/11244
POJ 2452 Sticks Problem ★ (单调栈+RMQ)
题解:
http://www.abandonzhang.com/archives/548
单调队列 应用:求区间最小(最大)值
求区间最小(最大)值,就维护一个递增的双端队列,队中保存原始序列的标号,当即将入队的元素的值比队尾的元素的值小(大)的时候就不断弹掉队尾,知道出现比它更小的值,当即将入队的元素队首元素的跨度(即将入队元素的序号到队首元素序列的区间)大于规定区间时就不断弹掉队首,直到跨度小于或等于所规定的区间。如此可保证队首元素为最小(最大)值,(但不能保证队尾就是原始序列中的最大(最小)值),并维护区间长度。
POJ 2823 Sliding Window (单调队列 裸题)
代码:
http://www.shaidaima.com/source/view/11243