其实单调队列就是一种队列内的元素有单调性的队列,由于其单调性因此常常会被用来维护区间最值或者下降DP的维数已达到降维来减小空间及时间的目的。c++
每个答案只与当前下标的前m个有关,因此能够用单调队列维护前m的个最小值,数组
考虑如何实现该维护的过程??优化
显然当前下标\(X\)的\(m\)个之前的元素(即下标小于\(X-M+1\)的元素)确定对答案没有贡献,因此能够将其从单调队列中删除。spa
对于两个元素\(A\),\(B\),下标分别为\(a\),\(b\),若是有\(A>=B\)&&\(a<b\)那么B留在队列里确定优于\(A\),所以能够将\(A\)删除。调试
维护队首:若是队首已是当前元素的\(m\)个以前,将\(head\)++,弹出队首元素code
维护队尾:比较\(q[tail]\)与当前元素的大小,若当前元素更优\(tail\)++,弹出队尾元素,直到能够知足队列单调性后加入当前元素。队列
考虑单调队列的时间复杂度:因为每个元素只会进队和出队一次,因此为\(O(n)\)。get
P3088[USACO13NOV]Crowded Cows S
#include <bits/stdc++.h> using namespace std; int a[2000100]; bool b[2000100]; int q[2000100];//数组模拟队列,更好调试 int head=1,tail=0; int n,m; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=1;i<=n;i++) { while(i-q[head]+1>m&&head<=tail)//若头结点在范围外 { head++;//弹出头结点 } while(a[i]<a[q[tail]]&&head<=tail)//若当前节点优于尾节点 { tail--;//弹出尾结点 } q[++tail]=i;//当前节点入队 } return 0; }
利用单调队列,能够优化涉及定长连续子区间求最值的线性dp问题
例题
P1725 琪露诺 琪露诺是最强的!!