题意:给定一个
n
∗
m
,
(
1
<
=
n
,
m
<
=
500
)
n*m,(1<=n,m<=500)
n∗m,(1<=n,m<=500)的只含有四种颜色标识的矩阵,定义合法矩阵为:
类似这样的四个块相同,且每个块内颜色一致,颜色分布位置也与之一致。
接下来有
3
e
5
3e5
3e5次询问,每次给出
(
r
1
,
c
1
)
,
(
r
2
,
c
2
)
(r1,c1),(r2,c2)
(r1,c1),(r2,c2),询问以
(
r
1
,
c
1
)
(r1,c1)
(r1,c1)为左上角,
(
r
2
,
c
2
)
(r2,c2)
(r2,c2)为右下角的区域内最大的合法子矩形的面积是多少。
我的思路:
四个数组预处理出每种颜色的二维前缀和,然后处理出以
(
i
,
j
)
(i,j)
(i,j)为左上角的每个点可以形成的最大矩形,对于每个点二分长度,check即可。接下来对于询问我就不会做了。。。。降不下来复杂度。
于是参考了题解:
题解的做法也是对于每个点计算最大矩形面积,但他的val[i][j]表示的是以(i,j)为合法矩形最靠里的那个点围绕该点形成的最大矩形。
然后预处理二维RMQ。
接下来的mid指的是**合法矩形块(合法矩形拆成四个小块)**的长度
那这样的话,对于询问,可以二分合法矩形块的长度mid,如果查到范围在
(
r
1
+
m
i
d
−
1
,
c
1
+
m
i
d
−
1
)
,
(
r
2
−
m
i
d
,
c
2
−
m
i
d
)
(r1+mid-1,c1+mid-1),(r2-mid,c2-mid)
(r1+mid−1,c1+mid−1),(r2−mid,c2−mid)内的最大值是大于等于4midmid则说明可能为答案。
因为预处理时处理出来的是最中心的点,故以该点为中心能构造出来的合法矩形的长度肯定在
[
0
,
v
a
l
[
i
]
[
j
]
]
[0,val[i][j]]
[0,val[i][j]]之间,故只要最大值满足大于等于4midmid,那么就说明肯定可以构造出来一个长度是mid的合法矩形。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=509;
//0 r 1 g 2 y 3 b;
int col[maxn][maxn][4];//前缀和;
char s[maxn][maxn];
bool check(int r1,int c1,int len,int i){
int r2=r1+len-1,c2=c1+len-1;
//cout<<r1<<" "<<c1<<" "<<r2<<" "<<c2<<" "<<col[r2][c2][i]-col[r1-1][c2][i]-col[r2][c1-1][i]+col[r1-1][c1-1][i]<<endl;
return col[r2][c2][i]-col[r1-1][c2][i]-col[r2][c1-1][i]+col[r1-1][c1-1][i]==(r2-r1+1)*(c2-c1+1);
}
bool check(int i,int j,int len){
int r1=i-len+1,c1=j-len+1;
return check(i-len+1,j-len+1,len,0)&&check(i-len+1,j+1,len,1)&&check(i+1,j-len+1,len,2)&&check(i+1,j+1,len,3);
}
int val[maxn][maxn][11][11];//RMQ;
void init(int n,int m){
int up1=log2(n)+1,up2=log2(m)+1;
for(int l1=0;l1<up1;l1++){
for(int l2=0;l2<up2;l2++){
if(!l1&&!l2) continue;
for(int i=1;(i+(1<<l1)-1)<=n;i++){
for(int j=1;(j+(1<<l2)-1)<=m;j++){
if(l2)val[i][j][l1][l2]=max(val[i][j][l1][l2-1],val[i][j+(1<<(l2-1))][l1][l2-1]);
else val[i][j][l1][l2]=max(val[i][j][l1-1][l2],val[i+(1<<(l1-1))][j][l1-1][l2]);
//cout<<val[l1][l2][i][j]<<endl;
}
}
}
}
}
int ask(int x1,int y1,int x2,int y2){
int p=log2(x2-x1+1),q=log2(y2-y1+1);
int ans=0;
ans=max(val[x1][y1][p][q],val[x1][y2-(1<<q)+1][p][q]);
ans=max(ans,max(val[x2-(1<<p)+1][y1][p][q],val[x2-(1<<p)+1][y2-(1<<q)+1][p][q]));
return ans;
}
int main(){
int n,m,q,r1,c1,r2,c2;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;++i){
scanf("%s",s[i]+1);
for(int j=1;j<=m;++j)
if(s[i][j]=='R') ++col[i][j][0];
else if(s[i][j]=='G') ++col[i][j][1];
else if(s[i][j]=='Y') ++col[i][j][2];
else ++col[i][j][3];
}
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
for(int k=0;k<4;++k)
col[i][j][k]+=col[i-1][j][k]+col[i][j-1][k]-col[i-1][j-1][k];
for(int i=1;i<n;++i)
for(int j=1;j<m;++j){
if(s[i][j]!='R') continue;
int l=1,r=min(min(i,j),min(n-i,m-j)),mid;
//cout<<i<<" "<<j<<" "<<l<<" "<<r<<endl;
while(l<=r){
mid=l+r>>1;
if(check(i,j,mid)) l=mid+1;
else r=mid-1;
}
val[i][j][0][0]=r*r*4;
//cout<<val[i][j][0][0]<<endl;
}
init(n,m);
while(q--){
scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
int l=1,r=min(r2-r1+1,c2-c1+1)/2,mid;
while(l<=r){
mid=l+r>>1;
if(ask(r1+mid-1,c1+mid-1,r2-mid,c2-mid)>=4*mid*mid) l=mid+1;
else r=mid-1;
}
printf("%d\n",r*r*4);
}
return 0;
}