平面图欧拉公式应用:1026T2

http://cplusoj.com/d/senior/p/SS231026B

考虑如何维护黑色连通块恰为1这个条件。我们可以直接运用平面图的欧拉公式。

对于“空腔”这个条件,我们可以先预处理,然后通过two-pointers+桶来实现

#include
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
//mt19937 rand(time(0));
//mt19937_64 rand(time(0));
//srand(time(0));
#define N 310
//#define M
//#define mo
struct node {
	int top, l, r;  
};
int n, m, i, j, k, T;
int ans, S[N][N], f[N][N], g[N][N], h[N][N]; 
int a[N], b[N], c[N], e[N], p[N], l, r, sum; 
int bin[N*N*2], mx[N], mnX[N*N], mxX[N*N], mnY[N*N], mxY[N*N]; 
int vis[N][N], tot, flg[N*N]; 
int dx[4]={0, 0, 1, -1}; 
int dy[4]={1, -1, 0, 0}; 
char s[N][N]; 
vector<node>G[N]; 
//vectorE[N]; 

void dfs(int x, int y) {
	vis[x][y]=1; 
	mnX[tot]=min(mnX[tot], x); mxX[tot]=max(mxX[tot], x); 
	mnY[tot]=min(mnY[tot], y); mxY[tot]=max(mxY[tot], y); 
	if(x==1 || y==1 || x==n || y==m) flg[tot]=1; 
	for(int k=0; k<4; ++k) {
		int newx=x+dx[k], newy=y+dy[k]; 
		if(newx<1 || newy<1 || newx>n || newy>m) continue; 
		if(vis[newx][newy]) continue; 
		if(s[newx][newy]!='0') continue; 
		dfs(newx, newy); 
	}
}

signed main()
{
//	freopen("in.txt", "r", stdin);
//	freopen("out.txt", "w", stdout); 
		freopen("village.in", "r", stdin);
	freopen("village.out", "w", stdout);
//	T=read();
//	while(T--) {
//
//	}
	memset(mnX, 0x3f, sizeof(mnX)); 
	memset(mnY, 0x3f, sizeof(mnY)); 
	n=read(); m=read(); 
	for(i=1; i<=n; ++i) scanf("%s", s[i]+1); 
	for(i=1; i<=n; ++i) for(j=1; j<=m; ++j) 
		if(s[i][j]=='0' && !vis[i][j]) ++tot, dfs(i, j); 
	for(i=1; i<=tot; ++i) {
		if(flg[i]) continue; 
//		printf("[%lld %lld] [%lld %lld]\n", mnX[i], mxX[i], mnY[i], mxY[i]); 
		G[mxX[i]+1].pb({mnX[i]-1, mnY[i], mxY[i]}); 
	}
	
	for(i=1; i<=n; ++i) for(j=1; j<=m; ++j) s[i][j]-='0'; 

	
//	for(i=1; i<=n; ++i, printf("\n")) 
//		for(j=1; j<=m; ++j) printf("%lld ", s[i][j]); 
//	printf("\n"); 
	for(j=1; j<=m; ++j) 
		for(i=1; i<=n; ++i) {
			f[i][j]=f[i-1][j]; 
			if(s[i][j] && s[i-1][j]) ++f[i][j]; 
			g[i][j]=g[i-1][j]; 
			if(s[i][j] && s[i][j+1]) ++g[i][j]; 
			h[i][j]=h[i-1][j]; 
			if(s[i][j] && s[i-1][j] && s[i][j+1] && s[i-1][j+1])
			 	++h[i][j]; 
			S[i][j]=S[i-1][j]; 
			if(s[i][j]) ++S[i][j]; 
		}
//	for(i=1; i<=n; ++i, printf("\n")) 
//		for(j=1; j<=m; ++j) printf("%lld ", h[i][j]); 
//	printf("\n"); 
//	for(i=1; i<=n; ++i) for(j=1; j<=m; ++j) 
//		S[i][j]=s[i][j]+S[i-1][j]+S[i][j-1]-S[i-1][j-1]; 
//	for(i=1; i<=n; ++i, printf("\n")) 
//		for(j=1; j<=m; ++j) printf("%lld ", g[i][j]); 
//	printf("\n"); 
			
	for(l=1; l<=n; ++l) {
		memset(mx, 0, sizeof(mx)); 
		for(r=l; r<=n; ++r) {
			for(auto t : G[r]) if(t.top>=l) {
				mx[t.r+1]=max(mx[t.r+1], t.l); 
			}
			for(i=1; i<=m; ++i) {
				p[i]=S[r][i]-S[l-1][i]; 
				a[i]=f[r][i]-f[l][i]; 
				b[i]=g[r][i]-g[l-1][i]; 
				c[i]=h[r][i]-h[l][i]; 
				e[i]=p[i]-a[i]-b[i]+c[i]; 
				e[i]+=e[i-1]; 
			}
//			printf("# [%lld %lld]\n", l, r); 
//			for(i=1; i<=m; ++i) printf("%lld ", mx[i]); printf("\n"); 
			bin[N*N]++; j=0; 
			for(i=1; i<=m; ++i) {
				while(j+1<mx[i]) bin[e[j]+N*N]--, ++j; 
//				printf("[%d %d]\n", j, i); 
				k=e[i-1]+p[i]-a[i]-1; 
				ans+=bin[k+N*N]; 
				bin[e[i]+N*N]++; 
				
			}
			while(j<=m) bin[e[j]+N*N]--, ++j; 
//			for(i=1; i<=m; ++i) {
//				// p-a-b+c=d+1
//			}
		}
	}
		
	printf("%lld", ans); 
	return 0;
}


你可能感兴趣的:(欧拉公式,连通块)