题目
题目链接: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 <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
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;
}