DTOJ#5164. 鬼渊传说

题面暂缺。

题解:
首先,对于不合法,有两种情况,分别处理。
①内含白色连通块。此时 O ( n 2 ) O(n^2) O(n2) 暴搜所有白色连通块以及最小包含子矩形。可以发现,答案矩形不能包含子矩形。这时考虑优化 O ( n 4 ) O(n^4) O(n4) 暴力。
我们只用枚举上、下、左边界,最大右边界可以发现对于左边界是单调增的。这时我们用桶维护。
②包含两个及以上的黑色连通块。这时我们可以发现对于两列 r r r r + 1 r+1 r+1,假如我们把这两列合并,可以发现若右边界满足①,那么和并这两列一定是合法的,不然必须有白色连通块内含。所以我们可以算出 Δ s z \Delta sz Δsz 的前缀和,就可以支持 O ( 1 ) O(1) O(1) 查询左端点的答案。

#include<bits/stdc++.h>
#define N 305
using namespace std;
inline int read(){
    
    
	int x=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){
    
    if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){
    
    x=(x<<1)+(x<<3)+s-'0';s=getchar();}
	return x*f;
}
int a[N][N],b[N][N],n,m,lx,ly,rx,ry,flag,st;
char s[N];
struct node{
    
    
	int sx,sy,tx,ty;
}sq[N*N];
inline bool cmp(node a,node b){
    
    return a.sx<b.sx;}
int dx[]={
    
    0,1,0,-1};
int dy[]={
    
    1,0,-1,0};
inline int pd(int x,int y){
    
    
	return x>=1&&x<=n&&y>=1&&y<=m;
}
void dfs(int x,int y){
    
    
	b[x][y]=1;
	lx=min(lx,x);ly=min(y,ly);
	rx=max(rx,x);ry=max(ry,y);
	for(int i=0;i<4;++i){
    
    
		int tx=x+dx[i],ty=y+dy[i];
		if(a[tx][ty])continue;
		if(!pd(tx,ty)){
    
    flag=1;continue;}
		if(b[tx][ty])continue;
		dfs(tx,ty);
	}
}
int ccl[N][N],fa[N*N*3],cnt1[N],cnt2[N],sum[N],tong[N*N<<1],zero=N*N,tl[N];
inline int id1(int x,int y){
    
    
	return (x-1)*m+y;
}
inline int id2(int x,int y,int typ){
    
    
	return (typ+1)*id1(n,m)+(x-1)*m+y;
}
inline int get(int x){
    
    return (fa[x]==x)?x:fa[x]=get(fa[x]);}
long long ans;
int main(){
    
    
	n=read(),m=read();
	for(int i=1;i<=n;++i){
    
    
		scanf("%s",1+s);
		for(int j=1;j<=m;++j){
    
    
			a[i][j]=s[j]-'0';
		}
	}
    for(int i=1;i<=n;++i){
    
    
    	for(int j=1;j<=m;++j){
    
    
    		if(a[i][j]==0&&!b[i][j]){
    
    
    			lx=n+1,ly=m+1,rx=0,ry=0;flag=0;
    			dfs(i,j);
    			if(!flag){
    
    
    				sq[++st].sx=lx,sq[st].sy=ly,sq[st].tx=rx,sq[st].ty=ry;
    			}
    		}
    	}
    }
    sort(sq+1,sq+1+st,cmp);
    for(int ux=1,top=1;ux<=n;++ux){
    
    
    	for(int i=1;i<=m;++i)cnt1[i]=cnt2[i]=0;
    	for(int i=ux;i<=n;++i)for(int j=1;j<=m;++j)ccl[i][j]=1e9;
    	for(int i=ux;i<=n;++i)for(int j=1;j<=m;++j)fa[id1(i,j)]=id1(i,j),fa[id2(i,j,0)]=id2(i,j,0),fa[id2(i,j,1)]=id2(i,j,1);
    	for(int i=1;i<=m;++i)tl[i]=m;
    	while(sq[top].sx<=ux&&top<=st)++top;
    	for(int dx=ux,j=top;dx<=n;++dx){
    
    
    		while(j<=st&&sq[j].sx<=dx){
    
    
    			ccl[sq[j].tx+1][sq[j].sy-1]=min(ccl[sq[j].tx+1][sq[j].sy-1],sq[j].ty);
    			++j;
    		}
    		for(int i=1;i<=m;++i){
    
    
    			tl[i]=min(tl[i],ccl[dx][i]);
    		}
    		for(int i=m-1;i;--i)tl[i]=min(tl[i],tl[i+1]);
    		for(int i=1;i<=m;++i){
    
    
    			if(!a[dx][i])continue;
    			if(a[dx][i])cnt1[i]++;
    			if(a[dx-1][i]&&dx>ux){
    
    
    				fa[get(id1(dx,i))]=get(id1(dx-1,i));
    				cnt1[i]--;
    				//cout<<sq[j].sx<<" "<<sq[j].sy<<" "<<sq[j].tx<<" "<<sq[j].ty<<endl;
    			}
    		}
    		for(int i=2;i<=m;++i){
    
    
    			//if(ux==1&&dx==4)cout<<i<<" "<<get(20)<<endl;
    			//if(ux==1&&dx==4&&i==m)cout<<get(id2(dx,i))<<" "<<fa[id2(dx-1,i)]<<" "<<get(31)<<endl;
    			if(a[dx][i-1]){
    
    
				    cnt2[i]++;
				    if(a[dx-1][i-1]&&dx>ux){
    
    
				    	fa[get(id2(dx,i-1,i&1))]=get(id2(dx-1,i-1,i&1));
				    	cnt2[i]--;
				    	
				    }
				}
				if(a[dx][i]){
    
    
				    cnt2[i]++;
				    if(a[dx-1][i]&&dx>ux){
    
    
				    	fa[get(id2(dx,i,i&1))]=get(id2(dx-1,i,i&1));
				    	cnt2[i]--;
				    }
				}
				if(a[dx][i-1]&&a[dx][i]){
    
    
					int fl=get(id2(dx,i-1,i&1)),fr=get(id2(dx,i,i&1));
					if(fl!=fr){
    
    
						fa[fl]=fr;
						cnt2[i]--;
					}
				}
				sum[i]=cnt2[i]-cnt1[i-1];
			}
			for(int i=2;i<=m;++i)sum[i]+=sum[i-1];
			int l=m,r=m;
			for(;l;--l){
    
    
				tong[sum[l]+zero]++;
				while(r>tl[l]&&r)tong[sum[r]+zero]--,--r;
				ans+=tong[sum[l]-cnt1[l]+1+zero];
			}
			while(r)tong[sum[r]+zero]--,--r;
			//memset(tong,0,sizeof(tong));
			//for(int i=1;i<=m;++i)cout<<ux<<" "<<dx<<" "<<i<<":"<<f[ux][dx][i]<<endl;
			/*if(ux==1&&dx==4){
				for(int i=1;i<=m;++i)cout<<cnt2[i]<<" ";cout<<endl;
			}*/
		}
	}
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/CSDNzhanghongyu/article/details/109710557