P1886 滑动窗口

题意::::现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。

解法  1)单调队列   2)线段树(n * log n)

       单调队列分析::

           考虑最小值情况::

               以该样例为例子说明::: 

               8 3

               1 3 -1 -3 5 3 6 7(在这里非常巧妙的就是用下标来维护窗口大小,保证均在合理范围内不越界)

               q表示队列入队的为下标

               1:队空 1 直接 入队 q={1}; 3 也直接入队 q={1,2};-1 则弹出前两项 q={3};

               2:  -3 则弹出前一项 q={4}; 5 直接入队 q={4,5}; 3 则弹出前一项 q={4,6};同时 队头下次操作越界 所以pop q={6};

               3:6 直接入队 q={6,7}; 7 也直接入队 q={6,7,8};同时 队头下次操作越界 所以pop q={7,8};

               1):当队列非空且队尾指向的下标元素小于当前或等于当前值---->不断弹出队尾

               2):下标入队尾

               3):判断队头所指向的下标是否越界,是则 pop

           最大值情况同样考虑

   

 1 #include <bits/stdc++.h>
 2 #define ll long long
 3 const int maxn=1e6+5;
 4 using namespace std;
 5 
 6 int ma[maxn];
 7 int a[maxn],b[maxn];
 8 deque<int>q;
 9 int main()
10 {
11     int n,k;
12     scanf("%d%d",&n,&k);
13     for(int i=1;i<=n;i++){
14         scanf("%d",&ma[i]);
15     }
16     //最小值
17     for(int i=1;i<=n;i++)
18     {
19         while(!q.empty()&&ma[q.back()]>=ma[i]){
20             q.pop_back();
21         }
22         q.push_back(i);
23         a[i]=ma[q.front()];
24         if(q.front()<=i-k+1&&i>=k){
25             q.pop_front();
26         }
27     }
28 
29     while(!q.empty())
30     {
31         q.pop_back();
32     }
33     for(int i=1;i<=n;i++)
34     {
35         while(!q.empty()&&ma[q.back()]<=ma[i]){
36             q.pop_back();
37         }
38         q.push_back(i);
39         b[i]=ma[q.front()];
40         if(q.front()<=i-k+1&&i>=k){
41             q.pop_front();
42         }
43     }
44     for(int i=k;i<=n;i++){
45         printf("%d ",a[i]);
46     }
47     printf("
");
48     for(int i=k;i<=n;i++){
49         printf("%d ",b[i]);
50     }
51     return 0;
52 }

               线段树更容易理解就不解释了,贴代码 (AC 900+ms  时间看着很慌,数据好点估计会卡死)

      

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 const int MOD=1e9+7;
 4 using namespace std;
 5 const int maxn=1e6+5;
 6 
 7 int Min[4*maxn],a[maxn],Max[4*maxn];
 8 int ma[maxn],mb[maxn];
 9 
10 void pushup(int rt)
11 {
12     Max[rt]=max(Max[2*rt],Max[2*rt+1]);
13     Min[rt]=min(Min[2*rt],Min[2*rt+1]);
14 }
15 void build(int l,int r,int rt)
16 {
17     if(l==r){
18         Max[rt]=a[l];
19         Min[rt]=a[l];
20         return ;
21     }
22     int mid=(l+r)>>1;
23     build(l,mid,2*rt);
24     build(mid+1,r,2*rt+1);
25     pushup(rt);
26 }
27 
28 int query1(int L,int R,int l,int r,int rt)
29 {
30     if(L<=l&&R>=r){
31         return Max[rt];
32     }
33     int mid=(l+r)>>1;
34     int ans=-1e9;
35     if(L<=mid){
36         ans=max(ans,query1(L,R,l,mid,2*rt));
37     }
38     if(R>mid){
39         ans=max(ans,query1(L,R,mid+1,r,2*rt+1));
40     }
41     return ans;
42 }
43 int query2(int L,int R,int l,int r,int rt)
44 {
45     if(L<=l&&R>=r){
46         return Min[rt];
47     }
48     int mid=(l+r)>>1;
49     int ans=1e9;
50     if(L<=mid){
51         ans=min(ans,query2(L,R,l,mid,2*rt));
52     }
53     if(R>mid){
54         ans=min(ans,query2(L,R,mid+1,r,2*rt+1));
55     }
56     return ans;
57 }
58 int main()
59 {
60     int n,m;
61     scanf("%d%d",&n,&m);
62     for(int i=1;i<=n;i++){
63         scanf("%d",&a[i]);
64     }
65     build(1,n,1);
66     for(int i=1;i<=n-m+1;i++)
67     {
68         ma[i]=query2(i,i+m-1,1,n,1);
69         mb[i]=query1(i,i+m-1,1,n,1);
70     }
71     for(int i=1;i<=n-m+1;i++){
72         printf("%d ",ma[i]);
73     }
74     printf("
");
75     for(int i=1;i<=n-m+1;i++){
76         printf("%d ",mb[i]);
77     }
78     return 0;
79 }
纵使单枪匹马,也要勇闯天涯
原文地址:https://www.cnblogs.com/sj-gank/p/11722821.html