Animals and Puzzle codeforces 713D 二维 rmq+二分+dp(算模板了)

本文介绍了一种解决矩阵中最大全1正方形查询的方法,通过动态规划预先计算每个位置的最大正方形边长,并利用二维ST表进行快速查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Owl Sonya gave a huge lake puzzle of size n × m to hedgehog Filya as a birthday present. Friends immediately started to assemble the puzzle, but some parts of it turned out to be empty — there was no picture on them. Parts with picture on it are denoted by 1, while empty parts are denoted by 0. Rows of the puzzle are numbered from top to bottom with integers from 1 to n, while columns are numbered from left to right with integers from 1 to m.

Animals decided to complete the picture and play with it, as it might be even more fun! Owl and hedgehog ask each other some queries. Each query is provided by four integers x1, y1, x2, y2 which define the rectangle, where (x1, y1) stands for the coordinates of the up left cell of the rectangle, while (x2, y2) stands for the coordinates of the bottom right cell. The answer to the query is the size of the maximum square consisting of picture parts only (only parts denoted by 1) and located fully inside the query rectangle.

Help Sonya and Filya answer t queries.

Input
The first line of the input contains two integers n and m (1 ≤ n, m ≤ 1000) — sizes of the puzzle.

Each of the following n lines contains m integers aij. Each of them is equal to 1 if the corresponding cell contains a picture and 0 if it’s empty.

Next line contains an integer t (1 ≤ t ≤ 1 000 000) — the number of queries.

Then follow t lines with queries’ descriptions. Each of them contains four integers x1, y1, x2, y2 (1 ≤ x1 ≤ x2 ≤ n, 1 ≤ y1 ≤ y2 ≤ m) — coordinates of the up left and bottom right cells of the query rectangle.

Output
Print t lines. The i-th of them should contain the maximum size of the square consisting of 1-s and lying fully inside the query rectangle.

Example
Input
3 4
1 1 0 1
0 1 1 0
0 1 1 0
5
1 1 2 3
2 1 3 2
3 2 3 4
1 1 3 4
1 2 3 4
Output
1
1
1
2
2

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

先用dp 把正方形转变成一个点的一个值 因为正方形的特点
dp[i][j]= min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1;
dp算出以i, j为右下角的正方形边长最大值
所以能得到当前正方形的最长边长

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

因为要查询的是子矩阵的最值,二维rmq 可以完成这个这种情况

因为 是 1000 所以 开到 11就好 时间复杂度是 O(log(n)log(m)n*m)+log(查询) 达到1e加上一些常数,是可以过的 5s

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n,m;
int val[N][N];
int dp[N][N][11][11];

void init()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            dp[i][j][0][0]=val[i][j];
        }
    }
    for(int ii=0;(1<<ii)<=n;ii++)  
    for(int jj=0;(1<<jj)<=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 getMax(int x1,int y1,int x2,int y2)  
{  
    int k1=0;  
    while((1<<(k1+1))<=x2-x1+1)k1++;  
    int k2=0;  
    while((1<<(k2+1))<=y2-y1+1)k2++;  
    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()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
            scanf("%d",&val[i][j]);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(!val[i][j]) val[i][j]=0;
            else 
                val[i][j]=min(min(val[i-1][j],val[i][j-1]),val[i-1][j-1])+1;
        }
    }
    init();
    int q;
    scanf("%d",&q);
    while(q--){
        int x1,x2,y1,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        int l=0,r=min(y2-y1+1,x2-x1+1);
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(getMax(x1+mid-1,y1+mid-1,x2,y2)>=mid) l=mid+1;
            else r=mid-1;
        }
        printf("%d\n",r );
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值