单调栈

来源:互联网 发布:淘宝上如何修改评价 编辑:程序博客网 时间:2024/04/29 02:25

单调栈


前置技能点:

  • 单调队列

闲话:

其实并不知道单调队列和单调栈的先后顺序,但既然我是先写单调队列的,那就把单调队列作为单调栈的前置技能点吧。

问题:

给定序列长度n,求每个点作为最大/最小值的最长区间。

思路:

对于每个点,可以直接向左向右枚举直到遇到比它小的数,复杂度为O(n2)

对于每个点,可以二分以它作为左端点的区间的长度,然后用线段树得到它是不是该长度的区间的最小值,同理向右处理。复杂度建树O(nlogn),对每个点的询问O((logn)2)

对于每个点,用倍增的方法得到它右边第一个比它小的元素,同理向右处理。敲起来比线段树快,还能加个小优化。复杂度同线段树。

概念引入:

对于单调队列中循环删除队尾的情况,有这么一种性质(假设该单调队列单调递增):

下面说的左边和右边指的是原序列中的位置,左边表示从该元素开始向id较小的元素看,右边这是向id较大的元素看。

  • 某个元素作为队尾被删除的条件:
    它右边的第一个比它小的数字即将进入队列时。

  • 循环队尾删除操作的终止条件:
    队列为空,或者队列中的队尾元素是即将压入元素左边的第一个比它小的元素。

所以可以取消掉单调队列的弹出队首操作,这样单调队列就是一个栈(其实觉得单调队列不算队列)了。

当有一个元素即将进栈时,需要先将栈内值大于它的函数全部弹栈,这个元素是被弹栈的元素右边第一个比它们小的元素,弹栈操作结束后,栈顶元素是该元素左边第一个比它小的元素。

若栈为空,则表示该元素是目前的最小值。

若整个序列进栈完毕,栈内剩余的每一个元素右边都没有比它小的元素。

复杂度:

预处理O(n),询问O(1),空间复杂度O(n)

拓展

同单调队列

例题

  • poj 2796
    给定一个长度为n(n<105)的非负整数序列a,定义函数f(l,r)=(minri=la[i])(ri=la[i]),求f(l,r)的最大值及其对应的lr
    解题报告
0 0