Loj#3461【USACO 2021.1 P】T3 Paint by Letters

【USACO 2021.1 P】T3 Paint by Letters

题目链接

题目大意

给出一张颜色图,每次询问一个区间内相同颜色块的个数。

解法

首先想到的当然是并查集,但这是区间查询做不了。。。

把相同颜色的点连边,那么同颜色块就是连通块,我们知道点数、边数,联想到欧拉平面图公式 (V - E + F = C - 1)

这里 (V)​ :点数, (E)​ :边数, (F)​ :面数, (C) :连通块数。

于是只需要求面数即可。

考虑在每个面的一个位置加上 (1)​​​ 的权值,做二维前缀和,此时就会有一些面被多统计,这样的面至多有 (O(N)) 个,特判一下即可。

#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int N=1010;
const int M=1e6+10;
int n,m,T,s[N][N],s1[N][N],s2[N][N],sum[N][N];
int t[N][N],p[M][2],cnt,bz[M];
int tot,d[M][2],st,en;
char a[N][N];
bool check(int x,int y){
	if(x<1 || x>=n || y<1 || y>=m)return 0;
	return !t[x][y];
}
void bfs(int x,int y){
	st=0;en=1;
	d[1][0]=x;d[1][1]=y;
	t[x][y]=cnt;
	while(st<en){
		++st;
		x=d[st][0];y=d[st][1];
		if(a[x][y]!=a[x+1][y] && check(x,y-1)){
			++en;
			d[en][0]=x;d[en][1]=y-1;
			t[x][y-1]=cnt;
		}
		if(a[x][y]!=a[x][y+1] && check(x-1,y)){
			++en;
			d[en][0]=x-1;d[en][1]=y;
			t[x-1][y]=cnt;
		}
		if(a[x+1][y]!=a[x+1][y+1] && check(x+1,y)){
			++en;
			d[en][0]=x+1;d[en][1]=y;
			t[x+1][y]=cnt;
		}
		if(a[x][y+1]!=a[x+1][y+1] && check(x,y+1)){
			++en;
			d[en][0]=x;d[en][1]=y+1;
			t[x][y+1]=cnt;
		}
	}
}
int main(){
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
	scanf("%d%d%d",&n,&m,&T);
	fo(i,1,n)
		scanf("%s",a[i]+1);
	fo(i,2,m)
		if(a[1][i]==a[1][i-1])++s[1][i];
	fo(i,2,n)
		if(a[i][1]==a[i-1][1])++s[i][1];
	fo(i,2,m)
		s[1][i]+=s[1][i-1];
	fo(i,2,n)
		s[i][1]+=s[i-1][1];
	fo(i,2,n){
		fo(j,2,m){
			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
			if(a[i][j]==a[i-1][j]){
				++s[i][j];
			}
			if(a[i][j]==a[i][j-1]){
				++s[i][j];
			}
		}
	}
	fo(i,1,n-1){
		fo(j,1,m-1){
			if(t[i][j])continue;
			++cnt;
			sum[i][j]=1;
			p[cnt][0]=i;p[cnt][1]=j;
			bfs(i,j);
		}
	}
	fo(i,1,n-1)
		fo(j,1,m-1)
			sum[i][j]+=sum[i-1][j] + sum[i][j-1] -sum[i-1][j-1];
	fo(o,1,T){
		int x,y,X,Y;
		scanf("%d%d%d%d",&x,&y,&X,&Y);
		int V=(X-x+1) * (Y-y+1),E=s[X][Y] - s[x][Y] - s[X][y] + s[x][y],
			F=sum[X-1][Y-1] - sum[x-1][Y-1] - sum[X-1][y-1] + sum[x-1][y-1] + 1;
		fo(i,x+1,X){
			if(a[i-1][y]!=a[i][y]){
				int id=t[i-1][y];
				if(bz[id]<o){
					bz[id]=o;
					if(x<=p[id][0] && p[id][0]<X && y<=p[id][1] && p[id][1]<Y)--F;
				}
			}else ++E;
			if(a[i-1][Y]!=a[i][Y]){
				int id=t[i-1][Y-1];
				if(bz[id]<o){
					bz[id]=o;
					if(x<=p[id][0] && p[id][0]<X && y<=p[id][1] && p[id][1]<Y)--F;
				}
			}
		}
		fo(i,y+1,Y){
			if(a[x][i-1]!=a[x][i]){
				int id=t[x][i-1];
				if(bz[id]<o){
					bz[id]=o;
					if(x<=p[id][0] && p[id][0]<X && y<=p[id][1] && p[id][1]<Y)--F;
				}
			}else ++E;
			if(a[X][i-1]!=a[X][i]){
				int id=t[X-1][i-1];
				if(bz[id]<o){
					bz[id]=o;
					if(x<=p[id][0] && p[id][0]<X && y<=p[id][1] && p[id][1]<Y)--F;
				}
			}
		}
		int C=V-E+F-1;
		printf("%d
",C);
	}
	
	return 0;
}
原文地址:https://www.cnblogs.com/Kelvin2005/p/15163713.html