【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;
}