CF713D Animals and Puzzle 题解

CF713D

有一个相当暴力的 $\mathcal{O}(nmt)$ 的做法是显然的,即对所有点求出以其为右下角的最大的全为 $1$ 的正方形的边长,记为 $f_{i,j}$。然后枚举询问的矩形中的点的 $f$ 的值,和边界判一下后的 $\max$ 就是答案了。

但是这样不好直接维护,由于矩形边界,并不能对 $f$ 取 $\max$。考虑转化为判定性问题,使用二分即可转化为求 $(x_1,y_1)$ 到 $(x_2-mid+1,y_2-mid+1)$ 的 $f$ 的极值是否大于等于 $mid$ 即可。由于查询已经带 $\log$ 了,使用 $\mathcal{O}(n\log^2n)-\mathcal{O}(1)$ 的二维 ST 表即可。

代码:

const int N = 1e3 + 10;
int n, m, Q, tot;
int a[N][N], log_2[N], f[11][11][N][N];

int qry(int xa, int ya, int xb, int yb) {
    int k1 = log_2[xb - xa + 1], k2 = log_2[yb - ya + 1];
    return max(f[k1][k2][xa][ya], max(max(f[k1][k2][xb - (1 << k1) + 1][ya], f[k1][k2][xa][yb - (1 << k2) + 1]), f[k1][k2][xb - (1 << k1) + 1][yb - (1 << k2) + 1]));
}

int main() {
    ios
    cin >> n >> m;
    for (int i = 2; i <= max(n, m); i++) log_2[i] = log_2[i >> 1] + 1;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> a[i][j];
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            if (a[i][j])
                f[0][0][i][j] = min(min(f[0][0][i - 1][j], f[0][0][i][j - 1]), f[0][0][i - 1][j - 1]) + 1;
    for (int k = 1; k <= 10; k++)
        for (int i = 1; i <= n - (1 << k) + 1; i++)
            for (int j = 1; j <= m; j++)
                f[k][0][i][j] = max(f[k - 1][0][i][j], f[k - 1][0][i + (1 << (k - 1))][j]);
    for (int k = 1; k <= 10; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m - (1 << k) + 1; j++)
                f[0][k][i][j] = max(f[0][k - 1][i][j], f[0][k - 1][i][j + (1 << (k - 1))]);
    for (int k1 = 1; k1 <= 10; k1++)
        for (int k2 = 1; k2 <= 10; k2++)
            for (int i = 1; i <= n - (1 << k1) + 1; i++)
                for (int j = 1; j <= m - (1 << k2) + 1; j++)
                    f[k1][k2][i][j] = max(f[k1][k2 - 1][i][j], f[k1][k2 - 1][i][j + (1 << (k2 - 1))]);
    cin >> Q;
    while (Q--) {
        int xa, ya, xb, yb;
        cin >> xa >> ya >> xb >> yb;
        int l = 1, r = min(xb - xa + 1, yb - ya + 1);
        while (l <= r) {
             int mid = (l + r) >> 1;
             if (qry(xa + mid - 1, ya + mid - 1, xb, yb) >= mid) l = mid + 1;
             else r = mid - 1;
        }
        cout << r << "\n";
    }
    return 0;
}
posted @ 2023-10-10 20:31  Pengzt  阅读(1)  评论(0编辑  收藏  举报  来源