E11【模板】单调队列 滑动窗口最值
E11【模板】单调队列 滑动窗口最值_哔哩哔哩_bilibili
// 单调队列 O(n) #include<iostream> 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]]); } }
1. 分步做,把矩形区的最值先按行压缩到到一格存储,后按列压缩到一格存储
2. 枚举行,横向滑动窗口,把每行的窗口最值存储在 maxv[i][j], minv[i][j]
3. 枚举列,竖向滑动窗口,把每列的窗口最值存储在 c[i], d[i]
#include<iostream> 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 q[N],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){ for(int i=1,h=1,t=0; i<=m; i++){ while(h<=t && q[h]<i-k+1) h++; while(h<=t && a[q[t]]<=a[i]) t--; q[++t]=i; b[i]=a[q[h]]; } } void get_min(int a[],int b[],int m){ for(int i=1,h=1,t=0; i<=m; i++){ while(h<=t && q[h]<i-k+1) h++; while(h<=t && a[q[t]]>=a[i]) t--; q[++t]=i; b[i]=a[q[h]]; } } 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号