1. 程式人生 > 實用技巧 >二維ST表

二維ST表

二維ST表。

​ 二維ST表咋寫捏?

\(f[x][y][k][l]\)表示左上角為\((x, y)\),右下角為\((x + 2^{k} -1 , y+2^l - 1)\)的矩形內的最值是多少。

​ 轉移的話和原來差不多,首先可以將矩形從中間橫著劈一刀:

\(f[x][y][k][l] = max/min(f[x][y][k - 1][l], f[x + 2 ^ {k - 1}][y][k - 1][l])\)

​ 然後還可以將矩形從中間豎著劈一刀:

\(f[x][y][k][l] = max/min(f[x][y][k][l - 1], f[x][y + 2^{l - 1}][k][l - 1])\)

​ 同樣的,還是可以實現\(O(1)\)查詢,假設現在要查詢左上角為\((x1, y1)\),右下角為\((x2 , y2)\)的矩形內的最值是多少。

​ 設\(p = lg[x2 - x1 + 1], q = lg[y2 - y1 + 1]\)

​ 如圖我們可以把查詢的大矩形分為四個小矩形,他們的座標分別是\((x1, y1, x1 + 2^p - 1, y1 + 2^q - 1)\),$ (x1, y2 - 2 ^ q + 1, x2 - 2^p + 1, y2)\(,\)(x2 - 2 ^ p + 1, y1, x2, y2 - 2^q + 1)\(,\) (x2 - 2^p + 1, y2 - 2^k + 1, x2, y2)\(。分別對應圖上的\)

w1,w2,w3,w4\(。對這四個小矩形的最值取\)max/min$,就是大矩形的最值了。

P2216 [HAOI2007]理想的正方形

​ 這道題可用二維ST表做。

題目連結

​ 對於這道題直接開\(f[1005][1005][11][11]\)是會爆空間的,但是我們發現題目要求的是正方形,其實就可以省去第三,四維;直接維護每個正方形的值就好了。

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}

const int N = 1005, inf = 2e9;
int n, m, k, ans;
int lg[N], f[N][N], g[N][N];

int main() {

    n = read(); m = read(); k = read();
    for(int i = 1;i <= n; i++)
        for(int j = 1;j <= m; j++) f[i][j] = g[i][j] = read();

    
    lg[0] = -1;
    for(int i = 1;i <= k; i++) lg[i] = lg[i >> 1] + 1;

    for(int s = 1;s <= lg[k]; s++) 
        for(int i = 1;i + (1 << s) - 1 <= n; i++)
            for(int j = 1;j + (1 << s) - 1 <= m; j++) {
                f[i][j] = max(max(f[i][j], f[i][j + (1 << (s - 1))]), max(f[i + (1 << (s - 1))][j], f[i + (1 << (s - 1))][j + (1 << (s - 1))]));
                g[i][j] = min(min(g[i][j], g[i][j + (1 << (s - 1))]), min(g[i + (1 << (s - 1))][j], g[i + (1 << (s - 1))][j + (1 << (s - 1))]));
            }

    ans = inf;
    for(int i = 1;i + k - 1 <= n; i++)
        for(int j = 1;j + k - 1 <= m; j++) {
            int x = i + k - 1, y = j + k - 1; 
            int maxn = max(max(f[i][j], f[x - (1 << lg[k]) + 1][j]), max(f[i][y - (1 << lg[k]) + 1], f[x - (1 << lg[k]) + 1][y - (1 << lg[k]) + 1]));
            int minn = min(min(g[i][j], g[x - (1 << lg[k]) + 1][j]), min(g[i][y - (1 << lg[k]) + 1], g[x - (1 << lg[k]) + 1][y - (1 << lg[k]) + 1]));
            ans = min(ans, maxn - minn);
        }
    
    printf("%d\n", ans);

    return 0;
}