大致题意:
有一个直方图,问你能在里面框出多大的矩形。暴力翻译
好的那么我们来做题。首先我们可以枚举矩形的左右两边,然后暴力枚举两边之间的最短矩形长度,然后强行乘起来
……10W的数据肯定过不了的……
所以我们珂以加一个优化:用线段树维护区间内最短的矩形长度好多了是不是
好吧其实我们可以在枚举右边缘时一个一个记录,可以加速到
但是它还是会超时……
有一种一般不达到上界的:
枚举左边界,然后使劲往右边扩展。
但是还是不够快!
卡常大法好!
所以我们就可以搬出一个救星:单调栈!
这个东西可以把我们的算法直接加速到(好多了)
(为了区分,我将每一个直方图中的长条称为长方形,将枚举得到的更大的图形称为矩形)
首先我们看这一幅图:
我们换一种搜法,枚举右边缘,再往左边扩展。
枚举右边缘,枚举到第4个长方形右边时会发现:
第四个长方形把前面的长方形全部挡住了!框起来的部分就没有用了!
那枚举第五个之后的右边缘时就完全不需要考虑前面的高度有多少啊!
所以我们可以把它合并成一个长方形,直接用最后的长方形高度当作它的高度。
另外,有一些枚举是没有意义的,比如:
这种情况下可以向右扩张得到一个更大的矩形。
结合以上两种情况,我们得到一个优化后的方法:
首先把第一个长方形压入栈。
从左往右搜索,遇到一个新的长方形就检测一下:它的高度是否高于栈顶的长方形?
如果高于,那就把它也压进栈。
如果它没有上一个长方形高,我们就把上一个长方形弹出来,把它的宽度加入新的长方形,再检测以它的高为高的矩形的面积。
说不清楚,上图
这3幅图描述了一次更新的过程。
蓝色的方框记录矩形可能扩展的宽度,红色方框记录前面的长方形可能得到的最大矩形。
最终,把最后一幅图中的蓝框框压进栈里。
这样的过程其实是维护了一个单调上升的序列(因为如果有下降就会被删掉),又因为它是一个栈,我们就叫它单调栈。
因为每一个长方形最多入栈一次,每一个原长方形也只能产生一个新长方形,所以时间复杂度是
呼~~~终于讲完了!
接下来是愉快的贴代码时间: