Monotone Queue + Offline Query - Parking Lot (CF480E)

Posted by wmguk on Sun, 06 Oct 2019 23:15:06 +0200

Portal


Analysis

link
Firstly, all the coordinates of inquiry are added to get the answer.
The initial answer is very good. You can set f[i,j] to indicate the maximum square edge length in the lower left corner (i,j).
Then, I F + 1 follows f[i,j]=min(f[i_1, j], f [i, j + 1] (+1) f[i,j]=min(f[i_1, j], f [i, j + 1] (+1), the upper right corner should be judged.
Of course, the lower left corner is obstacle f[i,j]=0.

Next, consider the time reversal.
First, we maintain left and right to indicate how long each position can extend from left to right.
When time goes backwards, it is equivalent to removing obstacles. The answer must be incremental.
Removing an obstacle requires only violent changes to the left and right of the line.
Next, we continue to determine whether there is an ans+1 (ans is the current answer) side of the square, there will be an ans+1, continue to do.
It is easy to know that the square must cross the barrier column.
So we can monotone the queue, get the length of each obstacle in the queue of ans+1 interval, how long can it extend to the left and right, if the total reaches ans+1, then determine the success.
The complexity is n2.


Code

#include<bits/stdc++.h>
#define re register
using namespace std;
const int N=2009;
int mark[N][N],f[N][N];
int Left[N][N],Right[N][N];
int ask[N][2],ans[N],now=0;
int n,m,k,x,y,head,tail,stk[N],b[N];
char st[N];
inline bool check(int len){
	head=1;tail=0;
	for(re int i=1;i<=n;++i){
		while(head<=tail&&Left[stk[tail]][y]>=Left[i][y]) tail--;
		stk[++tail]=i;
		while(stk[head]<=i-len) head++;
		b[i]=Left[stk[head]][y];
	}
	head=1;tail=0;
	for(re int i=1;i<=n;++i){
		while(head<=tail&&Right[stk[tail]][y]>=Right[i][y]) tail--;
		stk[++tail]=i;
		while(stk[head]<=i-len) head++;
		b[i]+=Right[stk[head]][y]-1;
	}
	for(re int i=1;i<=n;++i)
		if(i>=len&&b[i]>=len) return 1;
	return 0;
}
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(re int i=1;i<=n;++i){
		scanf("%s",st+1);
		for(re int j=1;j<=m;++j)
			if(st[j]=='X') mark[i][j]=1;
	}
	for(re int i=1;i<=k;++i){
		scanf("%d%d",&ask[i][0],&ask[i][1]);
		mark[ask[i][0]][ask[i][1]]=1;
	}
	for(re int i=1;i<=n;++i){
		for(re int j=m;j>=1;--j){
			if(mark[i][j]) continue;
			if(i==1||j==m) {
				f[i][j]=1;
				now=max(now,f[i][j]);
				continue;
			}
			f[i][j]=min(f[i-1][j],f[i][j+1]);
			if(!mark[i-f[i][j]][j+f[i][j]]) f[i][j]++;
			now=max(now,f[i][j]);
		}
	}
	for(re int i=1;i<=n;++i){
		for(re int j=1;j<=m;++j) if(mark[i][j]) Left[i][j]=0;else Left[i][j]=Left[i][j-1]+1;
		for(re int j=m;j>=1;--j) if(mark[i][j]) Right[i][j]=0;else Right[i][j]=Right[i][j+1]+1;
	}
	for(re int i=k;i>1;--i){
		ans[i]=now;
		x=ask[i][0];y=ask[i][1];
		mark[x][y]=0;
		for(re int j=1;j<=m;++j)
			if(mark[x][j]) Left[x][j]=0;
			else Left[x][j]=Left[x][j-1]+1;
		for(re int j=m;j>=1;--j)
			if(mark[x][j]) Right[x][j]=0;
			else Right[x][j]=Right[x][j+1]+1;
		while(check(now+1)) now++;
	}
	ans[1]=now;
	for(re int i=1;i<=k;++i) printf("%d\n",ans[i]);
	return 0;
}