1. 程式人生 > 其它 >Loj#3461【USACO 2021.1 P】T3 Paint by Letters

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\n",C);
	}
	
	return 0;
}