题目链接:https://jzoj.net/senior/#main/show/4817
给出一个 01 01 01矩阵,每次询问子矩阵中的最大 1 1 1正方形。
二分最大正方形的边长 m i d mid mid,那么对于询问 ( x , y ) ( x x , y y ) (x,y)(xx,yy) (x,y)(xx,yy)的子矩阵,我们其实就是要判断子矩阵 ( x + m i d − 1 , y + m i d − 1 ) ( x x , y y ) (x+mid-1,y+mid-1)(xx,yy) (x+mid−1,y+mid−1)(xx,yy)的最大值是否不小于 m i d mid mid。
二维 r m q rmq rmq即可。
时间复杂度 O ( n m log n log m + q log n ) O(nm\log n\log m+q\log n) O(nmlognlogm+qlogn)。
注意 l o g ( x ) log(x) log(x)需要预处理而不是在二分中求,否则时间复杂度就变成了 O ( q log 2 n ) O(q\log^2n) O(qlog2n)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include
#include
#include
#include
using namespace std;
const int N=1010,LG=10;
int n,m,Q,f[N][N],rmq[LG+1][LG+1][N][N],Log[N],power[LG+1];
int read()
{
int d=0; char ch=getchar();
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
return d;
}
inline int maxx(int wyc,int ak,int ioi,int orz)
{
return max(max(wyc,ak),max(ioi,orz));
}
inline bool check(int x,int y,int xx,int yy,int k)
{
if (x>xx || y>yy) return 0;
int logx=Log[xx-x+1],logy=Log[yy-y+1];
if (rmq[logx][logy][x][y]>=k || rmq[logx][logy][xx-power[logx]+1][yy-power[logy]+1]>=k) return 1;
if (rmq[logx][logy][xx-power[logx]+1][y]>=k || rmq[logx][logy][x][yy-power[logy]+1]>=k) return 1;
return 0;
}
int main()
{
freopen("square.in","r",stdin);
freopen("square.out","w",stdout);
for (int i=2;i<=1000;i++)
Log[i]=Log[i/2]+1;
power[0]=1;
for (int i=1;i<=10;i++)
power[i]=power[i-1]*2;
n=read(); m=read();
for (int i=1,x;i<=n;i++)
for (int j=1;j<=m;j++)
{
if (read()) f[i][j]=min(f[i][j-1],min(f[i-1][j],f[i-1][j-1]))+1;
rmq[0][0][i][j]=f[i][j];
}
for (int k=0;k<=LG;k++)
for (register int l=k?0:1;l<=LG;l++)
for (register int i=1;(!k && i<=n) || (k && i+power[k-1]<=n);i++)
for (register int j=1;(!l && j<=m) || (l && j+power[l-1]<=m);j++)
if (!k)
rmq[k][l][i][j]=max(rmq[k][l-1][i][j],rmq[k][l-1][i][j+power[l-1]]);
else if (!l)
rmq[k][l][i][j]=max(rmq[k-1][l][i][j],rmq[k-1][l][i+power[k-1]][j]);
else
rmq[k][l][i][j]=maxx(rmq[k-1][l-1][i][j],rmq[k-1][l-1][i+power[k-1]][j],rmq[k-1][l-1][i][j+power[l-1]],rmq[k-1][l-1][i+power[k-1]][j+power[l-1]]);
Q=read();
while (Q--)
{
int x,xx,y,yy,l=1,r=n,mid;
x=read(); y=read(); xx=read(); yy=read();
while (l<=r)
{
mid=(l+r)>>1;
if (check(x+mid-1,y+mid-1,xx,yy,mid)) l=mid+1;
else r=mid-1;
}
printf("%d\n",l-1);
}
return 0;
}