预备知识介绍:
1. 队列
- 队列 (queue) 是一种特殊的线性表,是符合“先进先出”(first in first out)原则的基本数据结构,因此也常被称作 FIFO 队列或公平队列。
- 一个队列由队首 (front)、队尾 (rear) 和储存元素的线性表构成。当元素入队时,队尾后移并向线性表中添加新元素;当元素出队时,删除线性表中队首指向的元素,队首后移。一般地,只在队尾入队,在队首出队。对队中元素的讨论都必须建立在队列非空的基础上,否则没有意义。
- C++ STL 中内置了 queue 容器,实现了普通队列的基本操作,使用时需引用 头文件。
2. 双端队列
- 双端队列 (deque) 打破了队列的出入队位置限制,允许元素从队首入队或从队尾出队。类似地,在 C++ STL 中内置了 deque 容器,实现了双端队列。
3. 单调队列
- 单调队列 (monotonic queue) 是指一种所储存的元素具有单调性的特殊双端队列,可根据具体的元素单调性分为单调递增队列、单调递减队列、单调不增队列、单调不减队列四种。前两种要求元素间具有严格的大小关系,不允许相等的元素同时出现在队列中,而后两者允许。
- 单调队列常常用于维护一个具有特殊性质的区间,求区间极值。一般会对区间长度或其他因素进行限制,因此队列中的元素常常为 (pos,val) 的二元组。在任意时刻,队列中元素的两个值都分别具有单调性,但其性质可能不同。如 pos 一般为单调上升,而 val 则四种情况都有可能。
- 新元素入队时,为了维护队列的单调性,要不断将队尾元素出队,直到当前元素入队后不会破坏队列单调性为止。取值计算时,为了保证对区间的限制是合法的,要将队首元素不断出队,直到队首元素满足对区间的限制为止。出队和入队的顺序可以调换。详见下面的例子。
- 在竞赛中单独考察单调队列的情况极少出现,但往往会配合动态规划,对其时间复杂度进行优化。近年来,NOI 系列赛事和部分省选都考察过。
举例分析
下面试举一例,分析单调队列的具体题目中的应用。
给定 n n 个数,分别为 a_1, a_2, \ldots, a_n