STL-Deque(双端队列)与单调队列的实现
前言:
STl是个好东西,虽然他在不开O2的条件下会跑的很慢,但他着实会让你的代码可读性大大提高,令你的代码看起来既简单又整洁。
双端队列:
顾名思义,双端队列是有两个头的,一个队首指针,一个队尾指针,先进先出或是先进后出都可以实现。
基本操作:
(1) deque<int> dq 定义一个int类型的双端队列dq
(2) deque<int> dq(15) 队列dq具有15个元素单位
(3) deque<int> dq(15,10) 队列dq内15个元素初始值均为10
(4) dq.push_back(x) 将x放入dq的末端
(5) dq.push_front(z) 将x放入dq的前端
(6) dq.size() 返回队列中元素的个数
(7) dq.pop_front() 弹出队列的前端元素
(8) dq.pop_back() 弹出队列的后端元素
(7) dq.front() 返回队列的前端元素
(8) dq.back() 返回队列的后端元素
代码实现:
1 #include<cstdio> 2 #include<queue> 3 using namespace std; 4 const int maxn=1e5+5; 5 deque<int> dq; 6 int a[maxn]={0,1,2,3,4,5,6,7,8,9,10}; 7 int main(){ 8 dq.push_front(a[1]),dq.push_front(a[2]),dq.push_front(a[3]); 9 dq.push_back(a[4]),dq.push_back(a[5]),dq.push_back(a[6]); 10 dq.push_front(a[7]),dq.push_front(a[8]); 11 dq.push_back(a[9]),dq.push_back(a[10]); 12 dq.pop_front(),dq.pop_front(); 13 dq.pop_back(),dq.pop_back(); 14 int n=dq.size();//n=6 15 for(int i=1;i<=n;i++){ 16 printf("%d ",dq.front()); 17 dq.pop_front(); 18 } 19 return 0; 20 }
小结:
双端队列不仅可以用来优化搜索,更能用来写单调队列这个神奇的xx来优化其他的一些东西(例如DP)
单调队列:
顾名思义,单调队列是单调递增或者是单调递减的一种队列,就像一个递增队列,若将数列1 6 5 3 8放入队列中,则队列的每一步变化为:1、1 6、1 5、1 3、1 3 8 。每当放入的元素使得队列不在单调,则弹出队尾的元素,直到使得队列元素单调。
代码实现:
1 #include<cstdio> 2 #include<queue> 3 using namespace std; 4 const int maxn=1e5+5; 5 deque<int> q_up; 6 deque<int> q_dw; 7 int a[maxn]={0,1,6,5,3,8}; 8 int main(){ 9 for(int i=1;i<=5;i++){ 10 while(q_up.size()&&q_up.back()>=a[i]) 11 q_up.pop_back(); 12 q_up.push_back(a[i]); 13 } 14 int n=q_up.size(); 15 for(int i=1;i<=n;i++){ 16 printf("%d ",q_up.front()); 17 q_up.pop_front(); 18 } 19 return 0; 20 }
当然,单调队列也可以用来维护滑动窗口的区间最大值和区间最小值。
例题_滑动窗口(洛谷P1886)
题目描述
现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。
1 #include<cstdio> 2 #include<queue> 3 using namespace std; 4 const int maxn=1e6+5; 5 struct cp{ 6 int ord,x; 7 }; 8 deque<cp> q1,q2; 9 int n,k; 10 int a[maxn],s1[maxn],s2[maxn]; 11 inline void q_max(cp e){ 12 while(q1.size()){ 13 cp q=q1.back(); 14 if(q.x>=e.x) q1.pop_back(); 15 else break; 16 } 17 while(q1.size()){ 18 cp q=q1.front(); 19 if(q.ord==e.ord-k) q1.pop_front(); 20 else break; 21 } 22 q1.push_back(e); 23 cp q=q1.front(); 24 if(e.ord-k>=0) s1[e.ord-k+1]=q.x; 25 } 26 inline void q_min(cp e){ 27 while(q2.size()){ 28 cp q=q2.back(); 29 if(q.x<=e.x) q2.pop_back(); 30 else break; 31 } 32 while(q2.size()){ 33 cp q=q2.front(); 34 if(q.ord==e.ord-k) q2.pop_front(); 35 else break; 36 } 37 q2.push_back(e); 38 cp q=q2.front(); 39 if(e.ord-k>=0) s2[e.ord-k+1]=q.x; 40 } 41 inline int read(){ 42 char ch=getchar(); 43 int x=0,f=1; 44 while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} 45 while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar(); 46 return x*f; 47 } 48 int main(){ 49 n=read(),k=read(); 50 for(int i=1;i<=n;i++) a[i]=read(); 51 for(int i=1;i<=n;i++){ 52 cp q; 53 q.ord=i,q.x=a[i]; 54 q_max(q),q_min(q); 55 printf("%d ",s1[i]) 56 } 57 for(int i=1;i<=n-k+1;i++) ; 58 putchar('\n'); 59 for(int i=1;i<=n-k+1;i++) printf("%d ",s2[i]); 60 return 0; 61 }
结构体类型的队列不知为何不能用 q.front().ord,所以代码显得特别冗长,如果有dalao可以解决这个问题,蒟蒻洗耳恭听!
(以上问题现已解决,附上代码)
1 #include<cstdio> 2 #include<queue> 3 using namespace std; 4 const int maxn=1e6+5; 5 struct cp{ 6 int ord,x; 7 }; 8 deque<cp> q1,q2; 9 int n,k; 10 int a[maxn],s1[maxn],s2[maxn]; 11 inline void q_max(cp e){ 12 while(q1.size()&&q1.back().x>=e.x) q1.pop_back(); 13 if(q1.size()&&q1.front().ord==e.ord-k) q1.pop_front(); 14 q1.push_back(e); 15 if(e.ord-k>=0) s1[e.ord-k+1]=q1.front().x; 16 } 17 inline void q_min(cp e){ 18 while(q2.size()&&q2.back().x<=e.x) q2.pop_back(); 19 if(q2.size()&&q2.front().ord==e.ord-k) q2.pop_front(); 20 q2.push_back(e); 21 if(e.ord-k>=0) s2[e.ord-k+1]=q2.front().x; 22 } 23 inline int read(){ 24 char ch=getchar(); 25 int x=0,f=1; 26 while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} 27 while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar(); 28 return x*f; 29 } 30 int main(){ 31 n=read(),k=read(); 32 for(int i=1;i<=n;i++) a[i]=read(); 33 for(int i=1;i<=n;i++){ 34 cp q=(cp){i,a[i]}; 35 q_max(q),q_min(q); 36 } 37 for(int i=1;i<=n-k+1;i++) printf("%d ",s1[i]); 38 putchar('\n'); 39 for(int i=1;i<=n-k+1;i++) printf("%d ",s2[i]); 40 return 0; 41 }
如有任何问题,蒟蒻洗耳恭听!