双端队列deque容器:
关于deque最常用的有这几个函数:
都是成员函数
双端队列模板题:【洛谷】P2952 [USACO09OPEN]牛线Cow Line
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<deque> 6 using namespace std; 7 8 int n, cnt; 9 deque<int> q; 10 11 int main() { 12 scanf("%d ", &n); 13 char s[21]; 14 for(int i=1; i<=n; ++i) { 15 gets(s); 16 if(s[0] == 'A') 17 if(s[2] == 'L') q.push_front(++cnt); 18 else q.push_back(++cnt); 19 if(s[0] == 'D') { 20 int m = 0, j = 1; 21 while(s[j]<'0' || s[j]>'9') ++j; 22 while(s[j]>='0' && s[j]<='9') 23 m = (m << 3) + (m << 1) + s[j] - 48, ++j; 24 while(m--) { 25 if(s[2] == 'L') q.pop_front(); 26 else q.pop_back(); 27 } 28 } 29 30 } 31 deque<int>::iterator it; 32 for(it=q.begin(); it!=q.end(); ++it) 33 printf("%d ", *it); 34 }
单调队列deque容器实现:
设一个数组a,可以修改某一个元素的值,求a中所有元素的最小(大)值
每次从头扫到尾的时间复杂度O(n2)太高了,st表虽然是O(1)查询但不支持修改
可以使用线段树O(n log2 n)来做但复杂度还是不够优秀,常数还大
单调队列登场了:
每次加入双端队列尾一个元素num时,从队尾将队列中所有比num大的元素都pop出去,再push_back(num)
这样就能实现单调队列了。
单调队列模板题:【洛谷】P1440 求m区间内的最小值
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<deque> 5 using namespace std; 6 7 const int MAXN = 2000000 + 1; 8 9 int n, m; 10 int a[MAXN]; 11 deque<int> q; 12 13 inline int read() { 14 int x=0, f=1; char ch=getchar(); 15 while(ch<'0' || ch>'9') { 16 if(ch == '-') f = -1; 17 ch = getchar(); 18 } 19 while(ch>='0' && ch<='9') 20 x=(x<<3)+(x<<1)+ch-48, ch=getchar(); 21 return x * f; 22 } 23 24 int main() { 25 n = read(), m = read(); 26 for(int i=1; i<=n; ++i) a[i] = read(); 27 puts("0"); 28 for(int i=1; i<n; ++i) { 29 if(i>m && q.front()==a[i-m]) q.pop_front(); 30 while(!q.empty() && q.back()>a[i]) q.pop_back(); 31 q.push_back(a[i]); 32 printf("%d ", q.front()); 33 } 34 }
单调队列优化DP:
在用单调队列优化DP的时候,每次除维护序列的单调性外,还需要把队首已经没有用的元素pop_front()掉
能够用单调队列优化的DP一般都长成这个样子:
f[i] = max/min{f[k]} + ...
1 ≤ k < i
而优化的其实是求最值的过程:将O(n)优化到了O(1).