codeforces 713D D. Animals and Puzzle 二分+二维rmq

题目链接

给一个01矩阵, 然后每个询问给出两个坐标(x1, y1), (x2, y2)。 问你这个范围内的最大全1正方形的边长是多少。

我们dp算出以i, j为右下角的正方形边长最大值。 然后用二维st表预处理出所有的最大值。 对于每个询问, 我们二分一个值mid, 查询(x1 + mid -1, y1 + mid -1), (x2, y2)这个范围内的最大值是否大于mid 。如果大于的话就说明在(x1, y1), (x2, y2)范围内存在一个边长为mid的正方形。

#include <bits/stdc++.h>
using namespace std;
#define pb(x) push_back(x)
#define ll long long
#define mk(x, y) make_pair(x, y)
#define lson l, m, rt<<1
#define mem(a) memset(a, 0, sizeof(a))
#define rson m+1, r, rt<<1|1
#define mem1(a) memset(a, -1, sizeof(a))
#define mem2(a) memset(a, 0x3f, sizeof(a))
#define rep(i, n, a) for(int i = a; i<n; i++)
#define fi first
#define se second
typedef complex <double> cmx;
typedef pair<int, int> pll;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int mod = 1e9+7;
const int inf = 1061109567;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
int dp[1001][1001][11][11], mm[1005];
void initRmq(int n, int m)
{
    mm[0] = -1;
    for(int i = 1; i <= max(n, m); i++) {
        mm[i] = ((i&(i-1)) == 0) ? mm[i-1] + 1 : mm[i-1];
    }
    for (int ii = 0; ii <= mm[n]; ii ++) {
        for (int jj = 0; jj <= mm[m]; jj ++) {
            if (ii + jj) {
                for (int i = 1; i + (1<<ii) - 1 <= n; i ++) {
                    for(int j = 1; j + (1<<jj) - 1 <= m; j ++) {
                        if (ii) {
                            dp[i][j][ii][jj] = max(dp[i][j][ii-1][jj], dp[i+(1<<(ii-1))][j][ii-1][jj]);
                        } else {
                            dp[i][j][ii][jj] = max(dp[i][j][ii][jj-1], dp[i][j+(1<<(jj-1))][ii][jj-1]);
                        }
                    }
                }
            }
        }
    }
}
int rmq(int x1, int y1, int x2, int y2)
{
    int k1 = mm[x2-x1+1];
    int k2 = mm[y2-y1+1];
    x2 = x2 - (1<<k1) + 1;
    y2 = y2 - (1<<k2) + 1;
    return max(max(dp[x1][y1][k1][k2], dp[x1][y2][k1][k2]), max((dp[x2][y1][k1][k2]), dp[x2][y2][k1][k2]));
}
int main()
{
    int n, m, x, q, x1, y1, x2, y2;
    cin>>n>>m;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            scanf("%d", &x);
            if (x)
                dp[i][j][0][0] = min(min(dp[i-1][j][0][0], dp[i][j-1][0][0]), dp[i-1][j-1][0][0]) + 1;
        }
    }
    initRmq(n, m);
    cin>>q;
    while (q--) {
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        int l = 0, r = min(x2 - x1, y2 - y1) + 1;
        int ans;
        while (l <= r) {
            int mid = l + r >> 1;
            if (rmq(x1 + mid - 1, y1 + mid - 1, x2, y2) >= mid) {
                ans = mid;
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
时间: 2024-10-10 21:19:33

codeforces 713D D. Animals and Puzzle 二分+二维rmq的相关文章

codeforces713D Animals and Puzzle(二维倍增)

引自:http://www.cnblogs.com/qscqesze/p/5929117.html 题意: 给你一个01矩阵,然后Q次询问,每次询问一个矩形区域中,最大的全一正方形的边长是多少. 思路: 首先考虑Dp,dp[i][j]表示以(i,j)位置为右下角,最大的正方形边长是多少,显然dp[i][j]=min(dp[i-1][j],dp[j][i-1],dp[i-1][j-1])+1 然后我们做出这个dp之后,我们怎么做呢? 直接二分答案,假设我们二分的答案为mid,显然在这个矩形区域的左

HDU 2888:Check Corners(二维RMQ)

http://acm.hdu.edu.cn/showproblem.php?pid=2888 题意:给出一个n*m的矩阵,还有q个询问,对于每个询问有一对(x1,y1)和(x2,y2),求这个子矩阵中的最大值,和判断四个角有没有等于这个最大值的. 思路:二维RMQ模板题.注意内存卡的挺紧的. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5

【bzoj1047】[HAOI2007]理想的正方形 二维RMQ

题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每行相邻两数之间用一空格分隔.100%的数据2<=a,b<=1000,n<=a,n<=b,n<=1000 输出 仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值. 样例输入 5 4 2 1 2 5 6 0 1

[hdu2888]二维RMQ

题意:求矩形内最大值.二维RMQ. 1 #pragma comment(linker, "/STACK:10240000,10240000") 2 3 #include <iostream> 4 #include <cstdio> 5 #include <algorithm> 6 #include <cstdlib> 7 #include <cstring> 8 #include <map> 9 #include

HDU2888 Check Corners(二维RMQ)

有一个矩阵,每次查询一个子矩阵,判断这个子矩阵的最大值是不是在这个子矩阵的四个角上 裸的二维RMQ 1 #pragma comment(linker, "/STACK:1677721600") 2 #include <map> 3 #include <set> 4 #include <stack> 5 #include <queue> 6 #include <cmath> 7 #include <ctime> 8

Cornfields poj2019 二维RMQ

Cornfields Time Limit:1000MS     Memory Limit:30000KB     64bit IO Format:%I64d & %I64u Submit Status Description FJ has decided to grow his own corn hybrid in order to help the cows make the best possible milk. To that end, he's looking to build the

P2216 [HAOI2007]理想的正方形(二维RMQ)

题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一行为3个整数,分别表示a,b,n的值 第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每行相邻两数之间用一空格分隔. 输出格式: 仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值. 输入输出样例 输入样例#1: 5 4 2 1 2 5 6 0 17 16 0 16 17 2 1 2 10 2

POJ 2019 Cornfields 二维RMQ

题目来源:POJ 2019 Cornfields 题意:求正方形二维区间最大最小值的差 思路:直接二维ST搞 试模版而已 #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int maxn = 255; int dp[maxn][maxn][8][8]; int dp2[maxn][maxn][8][8]; int a[maxn][maxn]; int n

POJ--2019--Cornfields【二维RMQ】

链接:http://poj.org/problem?id=2019 题意:给你一个n*n的矩阵,q次询问,每次询问给出左上角的坐标,询问以这个点为左上角的b*b的子矩阵中最大值和最小值的差. 思路:二维RMQ的基本应用,网上找的模板 这道题是USACO的,数据很水,暴力也能过. #include<cstring> #include<string> #include<fstream> #include<iostream> #include<iomanip