正题
题目链接:https://jzoj.net/senior/#contest/show/2956/2
题目大意
n∗mn*mn∗m的010101矩阵,每次询问(x1,y1,x2,y2)(x1,y1,x2,y2)(x1,y1,x2,y2)里的最大全111正方形。
解题思路
我们用fi,jf_{i,j}fi,j表示以(i,j)(i,j)(i,j)为右下角的全1正方形大小,然后对于询问(x1,y1,x2,y2)(x1,y1,x2,y2)(x1,y1,x2,y2)我们二分一个midmidmid。
然后判断(x1+mid−1,y1+mid−1,x2,y2)(x1+mid-1,y1+mid-1,x2,y2)(x1+mid−1,y1+mid−1,x2,y2)中最大的fff是否大于等于midmidmid即可。
最大值用二维RMQRMQRMQ即可。
codecodecode
#pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1100;
int n,m,T,f[N][N],g[N][N][10][10],ln[N];
int ask(int x1,int y1,int x2,int y2)
{int z1=ln[x2-x1+1],z2=ln[y2-y1+1];return max(max(g[x1][y1][z1][z2],g[x2-(1<<z1)+1][y2-(1<<z2)+1][z1][z2]),max(g[x2-(1<<z1)+1][y1][z1][z2],g[x1][y2-(1<<z2)+1][z1][z2]));
}
int main()
{freopen("square.in","r",stdin);freopen("square.out","w",stdout);scanf("%d%d",&n,&m);for(int i=2;i<=n;i++)ln[i]=ln[i/2]+1;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){int x;scanf("%d",&x);if(x)f[i][j]=min(f[i-1][j-1],min(f[i-1][j],f[i][j-1]))+1;g[i][j][0][0]=f[i][j];}for(int a=0;(1<<a)<=n;a++)for(int b=0;(1<<b)<=m;b++){if(!b&&!a) continue;for(int i=1;i+(1<<a)-1<=n;i++)for(int j=1;j+(1<<b)-1<=m;j++)if(!b) g[i][j][a][b]=max(g[i][j][a-1][b],g[i+(1<<a-1)][j][a-1][b]);else g[i][j][a][b]=max(g[i][j][a][b-1],g[i][j+(1<<b-1)][a][b-1]);}scanf("%d",&T);while(T--){int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);int l=0,r=min(x2-x1+1,y2-y1+1);while(l<=r){int mid=(l+r)/2;if(ask(x1+mid-1,y1+mid-1,x2,y2)>=mid) l=mid+1;else r=mid-1;}printf("%d\n",r);}
}