单调队列
前置技能点:
队列
问题:
对于一个长度为
n
的序列
struct Node{
int id;
int v;//value
}a[NodeNum];//a[i]的大小由成员变量v决定
思路:
可以以
可以通过线段树进行处理,从而减小查询任意一个区间的最值的复杂度,建树复杂度为 O(nlogn) ,查询复杂度为 O(logn) 。
还可以将
a
序列压入一个按
概念引入:
设
(minl+k−1i=la[i]).id=x
,
(minl+k−1i=l+1a[i]).id=x′
。
若
x==l
,则
x′>x
否则
x′==x
。
设
(minl+k−1i=l+1a[i]).id=y
若
a[l+k].v<=a[y].v
,则
minl+ki=l+1a[i]).id==l+k
否则
minl+ki=l+1a[i]).id==y
。
那么就可以维护一个单调递增的队列,用于存储当前区间的最小元素,以及当前区间内队列中每一个元素右边的子序列中的最小元素。
当求解
minl+k−1i=la[i]
时
若
queue[head].id==l−1
,则可以将它弹出队列。
同时将
a[l+k−1].v
与
queue[tail].v
进行大小判定,若
queue[tail].v>=a[l+k−1].v
则将队尾删除,循环判定直到队列为空或
queue[tail].v<a[l+k−1].v
为止。
复杂度:
预处理 O(n) ,询问 O(1) ,空间复杂度 O(n)
拓展:
- 对于弹出队首,删除队尾元素以及压入元素条件的判定
求凸包 - 对于其他性质的运用
单调栈