单调队列入门

Posted wsy107316

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单调队列入门相关的知识,希望对你有一定的参考价值。

单调队列这个名字就指明了它的性质——单调性,是一个单调的双端队列

下面列出deque的常用成员函数:来自:https://blog.csdn.net/morewindows/article/details/6946811

技术图片

 

 单调队列入门题目:P1886 滑动窗口 /【模板】单调队列

技术图片

 

 技术图片

 

 

这里我们只讨论最大值,最小值原理一样的

很明显,当我们在计算区间[ik+1,i]的最大值时,是不是区间[ik+1,i1]我们之前已经计算过了?那么我们是不是要保存上一次的结果呢(主要是最大值)?

这时,单调队列登场——单调队列主要有两个操作:删头去尾

1.删头

如果队列头的元素离开了我们当前操作的区间,那么这

个元素就没有任何用了,我们就要把它删掉

2.去尾

假设即将进入队列的元素为X,队列尾指针为tail这时我们要比较二者的大小:

1* X<q[tail此时q仍然保证着递减性,故直接将X插入队列尾

2*X>=q[tail此时,队列递减性被打破,此时我们做一下操作:

① 弹出队尾元素

因为当前的q[tail]不但不是最大值,对于以后的情况也不如X,所以要弹出

②重复执行①,直到满足X<q[tail]X<q[tail]或者队列为空为止

③将XX入队列

对于样例而言:

[1 3 -1] -3 5 3 6 7 
q={1},{3},{3,-1} output:3
1 [3 -1 -3] 5 3 6 7 
q={3,-1,-3} output:3
1 3 [-1 -3 5] 3 6 7
q={-1,-3},{-1,5},{5} output:5
1 3 -1 [-3 5 3] 6 7
q={5,3} output:5
1 3 -1 -3 [5 3 6] 7 
q={5,6},{6} output:6
1 3 -1 -3 5 [3 6 7]
q={6,7} output:7

由于每个元素最多入队一次,出队一次,所以时间复杂度为O(n)

当然,这题还可以用ST表和线段树来做,但都没有单调队列方便

实现:由于要对队首和队尾进行维护,所以我们需要使用双端队列

AC_Code

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 1e6+10;
 5 const ll inf=0x3f3f3f3f3f3f3f3f;
 6 #define dep(i,first,last) for(int i=first;i>=last;i--)
 7 #define rep(i,first,last) for(int i=first;i<=last;i++)
 8 #define lson l,mid,pt<<1
 9 #define rson mid+1,r,pt<<1|1
10 
11 template<typename T>void read(T &a){
12     T x=0,f=1;
13     char ch=getchar();
14     while( !isdigit(ch) ){
15         if( ch==-) f=0;
16         ch=getchar();
17     }
18     while( isdigit(ch) ){
19         x=(x<<1)+(x<<3)+ch-0;
20         ch=getchar();
21     }
22     a=f?x:-x;
23 }
24 
25 deque<int>q;
26 int a[maxn],n,m;
27 int main()
28 {
29     read(n);
30     read(m);
31     rep(i,1,n) read(a[i]);
32     rep(i,1,n){
33         while(!q.empty() && a[q.back()]>a[i]) q.pop_back();
34         q.push_back(i);
35         if( i>=m ){
36             while( q.front()<=i-m ) q.pop_front();
37             printf("%d ",a[q.front()]);
38         }
39     }
40     printf("
");
41     while(!q.empty()) q.pop_front();
42     rep(i,1,n){
43         while(!q.empty() && a[q.back()]<a[i]) q.pop_back();
44         q.push_back(i);
45         if( i>=m ){
46             while( q.front()<=i-m ) q.pop_front();
47             printf("%d ",a[q.front()]);
48         }
49     }
50     printf("
");
51     return 0;
52 }

 

以上是关于单调队列入门的主要内容,如果未能解决你的问题,请参考以下文章

单调队列入门

单调队列入门

⭐算法入门⭐《队列 - 单调队列》中等03 —— LeetCode 918. 环形子数组的最大和

⭐算法入门⭐《队列 - 单调队列》中等04 —— LeetCode 剑指 Offer 59 - II. 队列的最大值

单调队列/单调栈入门详解+题目推荐

单调栈&单调队列入门