单调队列 和 单调栈

单调队列

定义

有一个队列(双端队列), 队列中的元素满足下面四种状态的任何一种都为单调队列:

  • 单调递增 (如 1 2 3 5 9)
  • 单调不减 (如 1 2 3 3 5)
  • 单调递减 (如 9 5 3 2 1)
  • 单调不增 (如 5 3 3 2 1)

性质

 (以单增队列为例)
 插入时,需要将尾部大于此数的全部出队。
 删除时,根据需要使队首或者队尾的元素出队(所以要用双端队列)。
 每时每刻队首元素都代表着当前区间范围内的最小值。
 单调队列维护元素值的同时也要维护元素的下标,以便知道每个元素和整个区间的关系。

实现

int q[maxn], p[maxn], ft, rr;
for(int i = 1; i <= n; ++i) {
    while(rr > ft && q[rr-1] >= a[i]) --rr;
    q[rr++] = a[i], p[rr-1] = i;
    //if(p[ft]<k) ++ft;
}

应用

 个人对单调队列有以下几点感觉:
 单调队列多用于区间问题,而且大多数是区间长度或者其他的有限制的问题。
 单调队列的研究对象一般是某个元素,而非某个区间(个人感觉), 个人感觉要维护的基本上是某个元素的一些相关属性。
 有几个题目作为例子:

POJ - 2823 Sliding Window: 滑动窗口 单调队列
HDU - 3415 Max Sum of Max-K-sub-sequence : 单调队列
HDU - 3530 Subsequence : 单调队列

 另外单调队列还有一个大用处就是优化一种形式的dp, 由于我还没有研究到dp,这里就先放一放,列一下知识点和一个题目感受一下。

(以下言论来自百度百科, 不可全信)
做动态规划时常常会见到形如这样的转移方程:

f[x] = max or min { g(k) | b[x] <= k < x } + w[x]

其中b[x]随x单调不降,即b[1]<=b[2]<=b[3]<=…<=b[n]
(g[k]表示一个和k或f[k]有关的函数,w[x]表示一个和x有关的函数)

 这个方程怎样求解呢?我们注意到这样一个性质:如果存在两个数j, k,使得j <= k,而且g(k) <= g(j),则决策j是毫无用处的。因为根据b[x]单调的特性,如果j可以作为合法决策,那么k一定可以作为合法决策,并且k是一个比j要优的决策。因为k比j要优,(注意:在这个经典模型中,“优”是绝对的,是与当前正在计算的状态无关的),所以,如果把待决策表中的决策按照k排序的话,则g(k)必然是不降的。在此例中决策表即f[x].
这样,就引导我们使用一个单调队列来维护决策表。对于每一个状态f(x)来说,计算过程分为以下几步:

1、 队首元素出队,直到队首元素在给定的范围中。
2、 此时,队首元素就是状态f(x)的最优决策,
3、 计算g(x),并将其插入到单调队列的尾部,同时维持队列的单调性(不断地出队,直到队列单调为止)。

 重复上述步骤直到所有的函数值均被计算出来。不难看出这样的算法均摊时间复杂度是O(1)的。因此求解f(x)的时间复杂度从O(n^2)降到了O(n)。
 单调队列指一个队列中的所有的数符合单调性(单调增或单调减),在信息学竞赛的一些题目上应用,会减少时间复杂度.
 可以参考下面这道题理解

POJ - 3017 Cut the Sequence : 单调队列优化dp

单调栈

定义

 个人感觉这个栈和队列是差不多的,其实单调栈只要在单调队列的基础上,关掉队列的一个端点不就行了, 只能在一端操作就是栈了,所以在实际的编码中单调栈和单调队列是差不多的(还是个人感觉)。

性质

 同单调队列

实现

 同单调队列

应用

目前我做到的四道题都只是用来求一个问题的:
就是在一个数组中, 求一个元素和它向左向右不比它小的元素所能组成的最大的区间,就是它最远能扩展到的地方,这应该是单调栈最简单的应用了(还没做到难的)。

HDU - 1506 Largest Rectangle in a Histogram: 单调栈入门题

另外还有三道题和这题差不多,我这里给出题目链接, 读者可作为练习实验下。

POJ - 3250 Bad Hair Day
POJ - 2796 Feel Good (这题是此书上的习题)
HDU - 1505 City Game

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值