「晚间测试8」physics
题意:
最大正方形+修改操作,每个修改后查询最大正方形
解法:
当然是随机化乱搞啊(假装不是修改)
没修改,是wmz的视察(最大正方形),\(O(n^2)\)DP乱搞
带修改后,发现正着做十分费劲,考虑倒着做,即先把所有修改离线,并直接修改,然后从后往前还原,类似的思想在修改并查集里有所体现
记录每个点在当前列向上和向下分别能扩展的最远点,以上一次修改的点为中心,二分正方形长度,因为对于一个0变1的点,可能产生的新最大正方形一定包括修改点
二分的\(check\)函数,可以写一个单调队列,维护上下边界的最值,判断上下最值和滑动窗口长度是否不小于二分长度
没了
时间复杂度:\(O(n^2log)\)
有\(O(n^2)\)的做法,懒得写了,康康其他人的博客就行
bool check(int len,int x){
int head1=1,tail1=0,head2=1,tail2=0,last=0;
memset(q1,0,sizeof(q1));
memset(q2,0,sizeof(q2));
for(int j=1;j<=m;j++){
while(head1<=tail1&&up[x][j]>up[x][q1[tail1]])tail1--;
while(head1<=tail1&&j-q1[head1]+1>len)head1++;
if(a[x][j])q1[++tail1]=j;
else head1=j+1,tail1=j;
while(head2<=tail2&&down[x][j]<down[x][q2[tail2]])tail2--;
while(head2<=tail2&&j-q2[head2]+1>len)head2++;
if(a[x][j])q2[++tail2]=j;
else head2=j+1,tail2=j,last=j+1;
if(j-last+1>=len&&down[x][j-len+1]-up[x][j-len+1]+1>=len&&down[x][q2[head2]]-up[x][q1[head1]]+1>=len){return 1;}
}
return 0;
}
#define mid ((l+r)>>1)
int Binary(int l,int r,int x){
while(l<=r){
//if(x==5)cout<<mid<<" "<<check(mid,x)<<" "<<l<<" "<<r<<" "<<endl;
if(check(mid,x))l=mid+1;
else r=mid-1;
}
return l-1;
}
int main(){
freopen("physics.in","r",stdin);
freopen("physics.out","w",stdout);
n=read(),m=read(),q=read();
for(register int i=1;i<=n;++i)scanf("%s ",b[i]+1);
for(register int i=1;i<=n;++i){
for(register int j=1;j<=m;j++){
if(b[i][j]=='+')a[i][j]=1;
}
}
for(int i=1;i<=q;i++){
qx[i]=read();qy[i]=read();a[qx[i]][qy[i]]=0;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!a[i][j])f[i][j]=0;
else f[i][j]=min(f[i-1][j-1],min(f[i-1][j],f[i][j-1]))+a[i][j];
ans[q]=max(ans[q],f[i][j]);
}
}
a[qx[q]][qy[q]]=1;
for(int j=1;j<=m;j++){
for(int i=1;i<=n;i++){
if(!a[i-1][j]&&a[i][j])up[i][j]=i;
else if(a[i][j])up[i][j]=up[i-1][j];
}
}
for(int j=m;j>=1;j--){
for(int i=n;i>=1;i--){
if(!a[i+1][j]&&a[i][j])down[i][j]=i;
else if(a[i][j])down[i][j]=down[i+1][j];
}
}
for(int i=q-1,x,y,last=qx[q];i>=1;i--){
x=qx[i],y=qy[i];
ans[i]=max(Binary(1,n,last),ans[i+1]);
a[x][y]=1;//cout<<i<<endl;
for(int j=1;j<=n;j++){
if(!a[j-1][y]&&a[j][y])up[j][y]=j;
else if(a[j][y])up[j][y]=up[j-1][y];
else if(!a[j][y])up[j][y]=0;
}
for(int j=n;j>=1;j--){
if(!a[j+1][y]&&a[j][y])down[j][y]=j;
else if(a[j][y])down[j][y]=down[j+1][y];
else if(!a[j][y])down[j][y]=0;
}
last=x;
}
for(int i=1;i<=q;i++)printf("%d\n",ans[i]);
return 0;
}