【JZOJ4817】square

来源:互联网 发布:windows hook框架 编辑:程序博客网 时间:2024/06/05 19:44

Description

给一个由0和1描述的矩阵,给出t次询问,每次询问左上角(x1,y1),右下角为(x2,y2)的子矩阵中的最大正方形(要求全部由1组成)。

Solution

我们首先可以计算出以(x,y)为左下角的最大正方形。我们设Fx,y,那么有:

Fx,y={0if ax,y=0min(Fx1,y1,Fx1,y,Fx,y1)+1if ax,y=1

那么就变成了多个子矩阵的最值问题了。

于是我们有二维rmq,具体可以看一下。

然后就O(1)询问了!

等等,我们发现这好像有问题,要理解F的状态,仅仅只是右下角的最大正方形,那么可能会超过询问的子矩阵范围。

不虚,我们可以二分答案。

如下图,设当前二分的答案为mid,那么我们肯定要在左上角为(x1+mid1,y1+mid1),右下角为(x2,y2)的子矩阵中找最大值,这样才可以满足当前最大的Fx,y的一部分保证在子矩阵内。

这里写图片描述

Code

这题须卡常!

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#define fo(i,j,k) for(int i=j;i<=k;i++)#define fd(i,j,k) for(int i=j;i>=k;i--)#define N 1001#define max(a,b) ((a)>(b)?(a):(b))#define ll long longusing namespace std;int read(int &n){    char ch=' ';    int q=0,w=1;    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());    if(ch=='-') w=-1,ch=getchar();    for(;ch>='0' && ch<='9';ch=getchar()) q=q*10+ch-48;n=q*w;    return n;}int a[N][N];int f[N][N];int rmq[11][11][N][N];int n,m;void pre(){    fo(i,1,n)    fo(j,1,m) rmq[0][0][i][j]=f[i][j];    int p=int(log2(n)),q=int(log2(m));    fo(k,0,p)    fo(l,0,q)    if(k+l)    fo(i,1,n-(1<<k)+1)    fo(j,1,m-(1<<l)+1)    {        if(!k) rmq[k][l][i][j]=max(rmq[k][l-1][i][j],rmq[k][l-1][i][j+(1<<(l-1))]);        else if (!l) rmq[k][l][i][j]=max(rmq[k-1][l][i][j],rmq[k-1][l][i+(1<<(k-1))][j]);        else rmq[k][l][i][j]=max(rmq[k][l-1][i][j],rmq[k][l-1][i][j+(1<<(l-1))]);    }}int rmqmax(int x1,int y1,int x2,int y2){    int p=int(log2(x2-x1+1)),q=int(log2(y2-y1+1));    int m1=rmq[p][q][x1][y1];    int m2=rmq[p][q][x2-(1<<p)+1][y1];    int m3=rmq[p][q][x1][y2-(1<<q)+1];    int m4=rmq[p][q][x2-(1<<p)+1][y2-(1<<q)+1];    return max(max(m1,m2),max(m3,m4));}int main(){    freopen("square.in","r",stdin);    freopen("square.out","w",stdout);    read(n);read(m);    fo(i,1,n)    fo(j,1,m)    {        read(a[i][j]);        if(a[i][j])        {            f[i][j]=min(f[i-1][j],f[i][j-1]);            f[i][j]=min(f[i][j],f[i-1][j-1]);            f[i][j]++;        }        else f[i][j]=0;    }    pre();    int T;    read(T);    while(T--)    {        int x1,y1,x2,y2;        read(x1);read(y1);read(x2);read(y2);        int l=0,r=min(x2-x1+1,y2-y1+1);        while(l+1<r)        {            int mid=(l+r)/2;            if(rmqmax(x1+mid-1,y1+mid-1,x2,y2)<mid) r=mid;            else l=mid;        }        int tmp;        if(rmqmax(x1+r-1,y1+r-1,x2,y2)>=r) tmp=r;        else tmp=l;        printf("%d\n",tmp);    }}
1 0