【題目-理想的正方形】 二維單調隊列

理想的正方形 (二維單調隊列)

題目

題解

  • 題目很好做,主要學習一下二維單調隊列的寫法
  • 首先將每行各窗口內最值用單調隊列維護出來,保存在rmax
  • 接着對rmax各列,將每列最值用單調隊列維護出來,保存在cmax中,最後cmax中存的就是行和列窗口乘積範圍的二維區間最值
  • 最小值同理

代碼

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;
const int N = 2e3 + 5;

int n, m, z;
int w[N][N];
int res = 0x3f3f3f3f;
int q[N], h, t;

int rmax[N][N], rmin[N][N];
int cmax[N][N], cmin[N][N];


void get_max(int i){
    h = 0, t = -1;
    for(int j = 1; j < z; ++ j) {
        while(h <= t && w[i][j] >= w[i][q[t]]) t--;
        q[++ t] = j;
    }
    for(int j = z; j <= m; ++ j) {
        while(h <= t && q[h] <= j - z) h ++;
        while(h <= t && w[i][j] >= w[i][q[t]]) t --;
        q[++ t] = j;
        rmax[i][j] = w[i][q[h]];
    }
}

void get_min(int i) {
    h = 0, t = -1;
    for(int j = 1; j < z; ++ j) {
        while(h <= t && w[i][j] <= w[i][q[t]]) t --;
        q[++ t] = j;
    }
    for(int j = z; j <= m; ++ j) {
        while(h <= t && q[h] <= j - z) h ++;
        while(h <= t && w[i][j] <= w[i][q[t]]) t --;
        q[++ t] = j;
        rmin[i][j] = w[i][q[h]];
    }
}

void get_max_c(int j) {
    h = 0, t = -1;
    for(int i = 1; i < z; ++ i) {
        while(h <= t && rmax[i][j] >= rmax[q[t]][j]) t --;
        q[++ t] = i;
    }
    for(int i = z; i <= n; ++ i) {
        while(h <= t && q[h] <= i - z) h ++;
        while(h <= t && rmax[i][j] >= rmax[q[t]][j]) t --;
        q[++ t] = i;
        cmax[i][j] = rmax[q[h]][j];
    }
}

void get_min_c(int j) {
    h = 0, t = -1;
    for(int i = 0; i < z; ++ i){
        while(h <= t && rmin[i][j] <= rmin[q[t]][j]) t --;
        q[++ t] = i;
    }
    for(int i = z; i <= n; ++ i) {
        while(h <= t && q[h] <= i - z) h ++;
        while(h <= t && rmin[i][j] <= rmin[q[t]][j]) t --;
        q[++ t] = i;
        cmin[i][j] = rmin[q[h]][j];
    }
}

int main() {
    scanf("%d%d%d",&n, &m, &z);
    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(i);
        get_min(i);
    }
    for(int j = z; j <= m; ++ j) {
        get_max_c(j);
        get_min_c(j);
    }
    int res = 0x3f3f3f3f;
    for(int i = z; i <= n; ++ i)
        for(int j = z; j <= m; ++ j)
            res = min(res, cmax[i][j] - cmin[i][j]);
    
    printf("%d\n",res);
    
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章