E11【模板】单调队列 滑动窗口最值
E11【模板】单调队列 滑动窗口最值_哔哩哔哩_bilibili
维护区间 [i-k+1, i] 内的最值
// 单调队列 O(n) #include<bits/stdc++.h> using namespace std; const int N=1000010; int n,k,a[N]; deque<int> q; int main(){ scanf("%d%d",&n,&k); for(int i=1; i<=n; i++) scanf("%d",&a[i]); for(int i=1; i<=n; i++){ while(!q.empty() && q.front()<i-k+1) q.pop_front(); //队头弹出(比下标) while(!q.empty() && a[q.back()]>a[i]) q.pop_back(); //队尾弹出(比元素) q.push_back(i); //队尾压入(当前下标) if(i>=k) printf("%d ",a[q.front()]); //输出最小值 } puts(""); q.clear(); for(int i=1; i<=n; i++){ while(!q.empty() && q.front()<i-k+1) q.pop_front(); while(!q.empty() && a[q.back()]<a[i]) q.pop_back(); q.push_back(i); if(i>=k) printf("%d ",a[q.front()]); } }
// 单调队列 O(n) #include<bits/stdc++.h> using namespace std; const int N=1000010; int n,k,a[N],q[N]; int main(){ scanf("%d%d",&n,&k); for(int i=1; i<=n; i++) scanf("%d",&a[i]); for(int i=1,h=1,t=0; i<=n; i++){ while(h<=t && q[h]<i-k+1) h++; //队头弹出(比下标) while(h<=t && a[q[t]]>a[i]) t--; //队尾弹出(比元素) q[++t]=i; //队尾压入(当前下标) if(i>=k) printf("%d ",a[q[h]]); //输出最小值 } puts(""); for(int i=1,h=1,t=0; i<=n; i++){ while(h<=t && q[h]<i-k+1) h++; while(h<=t && a[q[t]]<a[i]) t--; q[++t]=i; if(i>=k) printf("%d ",a[q[h]]); } }
P2698 [USACO12MAR] Flowerpot S - 洛谷
1. 分步做,把矩形区的最值先按行压缩到到一格存储,后按列压缩到一格存储
2. 枚举行,横向滑动窗口,把每行的窗口最值存储在 maxv[i][j], minv[i][j]
3. 枚举列,竖向滑动窗口,把每列的窗口最值存储在 c[i], d[i]
#include<bits/stdc++.h> using namespace std; const int N=1010; int n,m,k; int w[N][N],minv[N][N],maxv[N][N]; //maxv[i][j]:第i行,j-k+1~j列的最大值 int a[N],b[N],c[N],d[N]; //a[i]:第i行,j-k+1~j列的最大值; c[i]:第i-k+1~i行,j-k+1~j列的最大值 void get_max(int a[],int b[],int m){ deque<int> q; for(int i=1; i<=m; i++){ while(q.size() && q.front()<i-k+1) q.pop_front(); while(q.size() && a[q.back()]<=a[i]) q.pop_back(); q.push_back(i); b[i]=a[q.front()]; } } void get_min(int a[],int b[],int m){ deque<int> q; for(int i=1; i<=m; i++){ while(q.size() && q.front()<i-k+1) q.pop_front(); while(q.size() && a[q.back()]>=a[i]) q.pop_back(); q.push_back(i); b[i]=a[q.front()]; } } int main(){ scanf("%d%d%d",&n,&m,&k); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) scanf("%d",&w[i][j]); for(int i=1; i<=n; i++){ //枚举行 get_max(w[i],maxv[i],m); //横滑窗口 get_min(w[i],minv[i],m); } int res=1e9; for(int j=k; j<=m; j++){ //枚举列 for(int i=1; i<=n; i++) a[i]=maxv[i][j],b[i]=minv[i][j]; get_max(a,c,n); //竖滑窗口 get_min(b,d,n); for(int i=k;i<=n;i++) res=min(res,c[i]-d[i]); } printf("%d\n",res); }
浙公网安备 33010602011771号