版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题目
CF
题目大意:
的矩阵,有一些点不能选。
次操作,每次都让一个点变成不可选,每次都问当前可选的最大正方形。
思路
首先,倒着来变为让一个点从不可选变为可选显然好做一些
首先倒着做答案肯定是单调不递减的,然后我们假设此次更改的点坐标是
,如果答案更新的话,新的答案构成的矩形肯定会包含
这个点我们假设当前答案是
于是我们要尝试
是否可以(因为似乎一步确定
有些困难),我们不妨把每个点向上最高和向下最深能到达的坐标记录为
和
(代码里好像写反了。。。),于是相当于查询包含这个点的宽度为
的区间最值查询,如果我们采用线段树,那么时间复杂度为
,可过
但是这也是单调队列经典应用,时间复杂度
代码
//#pragma GCC optimize(2)
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<climits>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
int read(){
bool f=0;int x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=1;c=getchar();}
while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return !f?x:-x;
}
#define lch (i<<1)
#define rch (i<<1|1)
#define MAXN 2000
#define INF 0x3f3f3f3f
char S[MAXN+5][MAXN+5];
int m,high[MAXN+5][MAXN+5],low[MAXN+5][MAXN+5];
int Q[MAXN+5],X[MAXN+5],Y[MAXN+5],Ans[MAXN+5],a[MAXN+5];
bool check(int row,int len){
int head=1,tail=0;
for(int j=1;j<=m;j++){
while(head<=tail&&high[row][Q[tail]]>=high[row][j]) tail--;
Q[++tail]=j;
while(Q[head]+len<=j) head++;
a[j]=high[row][Q[head]];
}
head=1,tail=0;
for(int j=1;j<=m;j++){
while(head<=tail&&low[row][Q[tail]]>=low[row][j]) tail--;
Q[++tail]=j;
while(Q[head]+len<=j) head++;
a[j]+=low[row][Q[head]]-1;
}
for(int j=len;j<=m;j++)
if(a[j]>=len) return 1;
return 0;
}
int f[MAXN+5][MAXN+5];
int main(){
int n=read();m=read();int q=read();
for(int i=1;i<=n;i++)
scanf("%s",S[i]+1);
for(int i=1;i<=q;i++){
X[i]=read(),Y[i]=read();
S[X[i]][Y[i]]='X';
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(S[i][j]=='X') high[i][j]=0;
else high[i][j]=high[i-1][j]+1;
for(int i=n;i>=1;i--)
for(int j=1;j<=m;j++)
if(S[i][j]=='X') low[i][j]=0;
else low[i][j]=low[i+1][j]+1;
int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(S[i][j]=='X')
f[i][j]=0;
else f[i][j]=min(f[i-1][j],min(f[i][j-1],f[i-1][j-1]))+1;
ans=max(ans,f[i][j]);
}
for(int t=q;t>=1;t--){
Ans[t]=ans;
S[X[t]][Y[t]]='.';
for(int i=1;i<=n;i++)
if(S[i][Y[t]]=='X') high[i][Y[t]]=0;
else high[i][Y[t]]=high[i-1][Y[t]]+1;
for(int i=n;i>=1;i--)//
if(S[i][Y[t]]=='X') low[i][Y[t]]=0;
else low[i][Y[t]]=low[i+1][Y[t]]+1;
while(check(X[t],ans+1)) ans++;
}
for(int i=1;i<=q;i++)
printf("%d\n",Ans[i]);
return 0;
}
思考
以后不要求强制在线一定要考虑离线,对于单调队列解决的问题一定要熟悉