E11【模板】单调队列 滑动窗口最值

E11【模板】单调队列 滑动窗口最值_哔哩哔哩_bilibili

 

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

维护区间 [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 - 洛谷

P1440 求m区间内的最小值 - 洛谷

P2032 扫描 - 洛谷

P2216 [HAOI2007] 理想的正方形 - 洛谷

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);
}

 

posted @ 2023-04-10 09:24  董晓  阅读(1953)  评论(0)    收藏  举报