1. 程式人生 > >●CodeForces 480E Parking Lot

●CodeForces 480E Parking Lot

com work 單調隊列 ORC UC 這一 lan define 表示

題鏈:

http://codeforces.com/problemset/problem/480/E
題解:

單調隊列,逆向思維
(在線的話應該是分治做,但是好麻煩。。)
離線操作,逆向考慮,
最後的狀態可以用O(N*M)的dp得出最大正方形邊長。
然後反向一個一個的把障礙變回非障礙,顯然答案不會變小。
維護好up[i][j],down[i][j],分別表示從(i,j)位置向上向下有多長的連續非障礙。
不難發現,如果有更大的答案的話,那麽必然包含當前改變的位置的那一行的某些格子。
所以確定了在這一行上尋找是否有更大的答案,
然後就用單調隊列維護來求出當前行上的最大正方形即可。


代碼:

#include<bits/stdc++.h>
#define MAXN 2005
using namespace std;
struct CMD{int x,y,ans;}C[MAXN];
bool graph[MAXN][MAXN];
int up[MAXN][MAXN],down[MAXN][MAXN];
int N,M,K,ANS;
void update(int j){
	for(int i=1;i<=N;i++)
		up[i][j]=graph[i][j]?up[i-1][j]+1:0;
	for(int i=N;i>=1;i--)
		down[i][j]=graph[i][j]?down[i+1][j]+1:0;
}
void prework(){
	static int dp[MAXN][MAXN];
	for(int i=1;i<=N;i++)
		for(int j=1;j<=M;j++){
			if(graph[i][j]==0) dp[i][j]=0;
			else dp[i][j]=min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1;
			ANS=max(ANS,dp[i][j]);
		}
	for(int j=1;j<=M;j++) update(j);
}
int main(){
	char ch;
	scanf("%d%d%d",&N,&M,&K);
	for(int i=1;i<=N;i++)
		for(int j=1;j<=M;j++)
			scanf(" %c",&ch),graph[i][j]=ch==‘.‘?1:0;
	for(int i=1;i<=K;i++)
		scanf("%d%d",&C[i].x,&C[i].y),graph[C[i].x][C[i].y]=0;
	prework(); C[K].ans=ANS;
	static int ql[MAXN],qr[MAXN],qll,qlr,qrl,qrr;
	for(int i=K,ret,x,l,r,h;i>=1;i--){
		ret=0; x=C[i].x;
		graph[C[i].x][C[i].y]=1;
		update(C[i].y);
		qll=qrl=l=1; qlr=qrr=r=0;
		while(l<=M){
			h=-233;
			if(l<=r){
				h=up[x][ql[qll]]+down[x][qr[qrl]]-1;
				ret=max(ret,min(h,r-l+1));
			}
			if(r<M&&(h==-233||h>=r-l+1)){
				r++;
				while(qll<=qlr&&up[x][ql[qlr]]>=up[x][r]) qlr--; ql[++qlr]=r;
				while(qrl<=qrr&&down[x][qr[qrr]]>=down[x][r]) qrr--;qr[++qrr]=r;
			}
			else{
				l++;
				while(qll<=qlr&&ql[qll]<l) qll++;
				while(qrl<=qrr&&qr[qrl]<l) qrl++;
			}
		}
		ANS=max(ret,ANS);
		C[i-1].ans=ANS;
	}
	for(int i=1;i<=K;i++) printf("%d\n",C[i].ans);	
	return 0;
}

  

●CodeForces 480E Parking Lot