题目大意
给你一个N∗M的矩阵,矩阵中每个位置为0或
Q≤106
解题思路
首先一个很直观的思路就是先预处理出数组p以每个个点为右下角,最大的全
dp[i][j]=min(min(dp[i−1][j],dp[i][j−1]),dp[i−1][j−1])+1
那么对于一个矩形中的最大边长我们可以先二分一个长度len。然后询问预处理中左上角为(x1+len−1,y1+len−1),右下角为(x2,y2)这个矩阵中p数组的最大值是否大于
那么现在的问题就变成了求一个矩阵中的最大值,那么很自然的就想到了二维rmq,介绍如下。
二维rmq
我们可以设rmq[i][j][x][y]表示以(x,y)为右下角,左上角为(x−2i+1,y−2j+1)的矩阵中的最大值。原理跟一维rmq类似。对于特殊的i=0或j=0的情况,根一维rmq一样
if(i==0) rmq[i][j][k][l]=max(rmq[i][j−1][k][l],rmq[i][j−1][k][l−Pow[j−1]]);if(j==0) rmq[i][j][k][l]=max(rmq[i−1][j][k][l],rmq[i−1][j][k−Pow[i−1]][l])
否则我们只需把当前矩形拆成两个求最大值
rmq[i][j][k][l]=max(rmq[i][j−1][k][l],rmq[i][j−1][k][l−Pow[j−1]])
而询问时只要把询问的矩形分成四个矩形询问就可以了
int lx=log[x2−x1+1],ly=log[y2−y1+1];Ans=max(max(rmq[lx][ly][x2][y2],rmq[lx][ly][x1+Pow[lx]−1][y1+Pow[ly]−1]),max(rmq[lx][ly][x2][y1+Pow[ly]−1],rmq[lx][ly][x1+Pow[lx]−1][y2]));
程序
//YxuanwKeith
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 1e3 + 5, MAXQ = 10;
int n, m, t, rmq[MAXQ][MAXQ][MAXN][MAXN], log[MAXN], Pow[MAXQ];
void Prepare() {
Pow[0] = 1;
for (int i = 0, j = 1; j < MAXN; i ++, j *= 2) log[j] = i;
for (int i = 1; i < MAXN; i ++) log[i] = max(log[i], log[i - 1]);
for (int i = 1; i < MAXQ; i ++) Pow[i] = Pow[i - 1] * 2;
for (int i = 2; i <= n; i ++)
for (int j = 2; j <= m; j ++)
if (rmq[0][0][i][j]) rmq[0][0][i][j] = min(min(rmq[0][0][i - 1][j], rmq[0][0][i][j - 1]), rmq[0][0][i - 1][j - 1]) + 1;
for (int i = 0; i < MAXQ; i ++)
for (int j = 0; j < MAXQ; j ++) {
if (i == 0 && j == 0) continue;
for (int k = Pow[i]; k <= n; k ++)
for (int l = Pow[j]; l <= m; l ++) {
if (i == 0) rmq[i][j][k][l] = max(rmq[i][j - 1][k][l], rmq[i][j - 1][k][l - Pow[j - 1]]); else
if (j == 0) rmq[i][j][k][l] = max(rmq[i - 1][j][k][l], rmq[i - 1][j][k - Pow[i - 1]][l]); else
rmq[i][j][k][l] = max(rmq[i][j - 1][k][l], rmq[i][j - 1][k][l - Pow[j - 1]]);
}
}
}
int Get(int x1, int y1, int x2, int y2) {
int lx = log[x2 - x1 + 1], ly = log[y2 - y1 + 1];
return max(max(rmq[lx][ly][x2][y2], rmq[lx][ly][x1 + Pow[lx] - 1][y1 + Pow[ly] - 1]), max(rmq[lx][ly][x2][y1 + Pow[ly] - 1], rmq[lx][ly][x1 + Pow[lx] - 1][y2]));
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
scanf("%d", &rmq[0][0][i][j]);
Prepare();
scanf("%d", &t);
for (int i = 1; i <= t; i ++) {
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
int l = 1, r = min(y2 - y1 + 1, x2 - x1 + 1), Ans = 0;
while (l <= r) {
int Mid = (l + r) >> 1;
if (Get(x1 + Mid - 1, y1 + Mid - 1, x2, y2) >= Mid) Ans = Mid, l = Mid + 1; else
r = Mid - 1;
}
printf("%d\n", Ans);
}
}