P1886 滑动窗口
Posted sj-gank
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
以上是关于P1886 滑动窗口的主要内容,如果未能解决你的问题,请参考以下文章