单调队列--P1886 滑动窗口 /【模板】单调队列

*传送

**单调队列的模板题(做很多题的前置准备)

本题我们维护一个从大到小/从小到大的单调队列即可。拿最大值来举例:对于新加进来的数,如果比队尾小我们就加进来,否则为了维护单调性我们从队尾弹出比当前值小的值。不难证明这些弹出的值不会是任何一个滑动窗口的答案。对于窗口的限定长度,我们只需要每次判断队首元素所在位置是否超过窗口长度,超过弹出即可,后输出队首(即当前队列中的最大值)即可。

代码如下:(感觉还是挺简洁易懂的)

 

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <queue>
 5 using namespace std;
 6 int q1[1000005],q2[1000005];
 7 int n,k,a[1000005];
 8 void maxx(){
 9     int head=1,t=0;
10     for (int i = 1;i <= n;i++){
11         while(head<=t&&q1[head]+k<=i) head++;//查看队首是否超过限定长度,超过就弹出 
12         while(head<=t&&a[i]>a[q1[t]]) t--;//维护单调性 
13         q1[++t]=i;
14         if (i>=k) cout<<a[q1[head]]<<" ";
15     }
16 }
17 void minn(){
18     int head=1,t=0;
19     for (int i = 1;i <= n;i++){
20         while(head<=t&&q2[head]+k<=i) head++;//查看队首是否超过限定长度,超过就弹出 
21         while(head<=t&&a[i]<a[q2[t]]) t--;//维护单调性 
22         q2[++t]=i;
23         if (i>=k) cout<<a[q2[head]]<<" ";
24     }
25 }
26 int main(){
27     scanf ("%d%d",&n,&k);
28     for (int i = 1;i <= n;i++) scanf ("%d",&a[i]);
29     minn();
30     cout<<endl;
31     maxx();
32     return 0;
33 }

 

posted @ 2020-03-13 16:34  小又又  阅读(253)  评论(0编辑  收藏  举报