二維ST表
阿新 • • 發佈:2020-09-18
二維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)\(。分別對應圖上的\)
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; }