Loj#3461【USACO 2021.1 P】T3 Paint by Letters
阿新 • • 發佈:2021-08-19
【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; }