[NOIP2019模拟赛][AT2381] Nuske vs Phantom Thnook
评测姬好快啊(港记号?)暴力40pts变成60pts
因为题目说了保证蓝色点两两之间只有一条路径,所以肯定组成了一棵树,而对于每次询问的x1,y1,x2,y2的子矩阵中就存在着一个森林
不难知道对于一个森林,其中树(联通块)的数量为$V-E$(V为节点数,E为边数)
也就是说对于每一个询问,只要求出蓝色节点数减去边数的答案就好了
点数和边数都可以用二维前缀和求,其中边可以分横边和竖边分别记录
1 #pragma GCC optimize("Ofast") 2 #include<bits/stdc++.h> 3 using namespace std; 4 inline int read(){ 5 int ans=0,f=1;char chr=getchar(); 6 while(!isdigit(chr)){if(chr=='-')f=-1;chr=getchar();} 7 while(isdigit(chr)) {ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();} 8 return ans*f; 9 }const int M = 2005; 10 int n,m,Q,s[2005][2005],v[2005][2005],sx,sy,tx,ty,ans; 11 int dx[]={0,1,0,-1}, 12 dy[]={1,0,-1,0}; 13 char a[2005][2005]; 14 void dfs(int x,int y){ 15 v[x][y]=1; 16 for(int i=0;i<4;i++){ 17 int fx=x+dx[i],fy=y+dy[i]; 18 if(v[fx][fy]||fx<sx||fx>tx||fy<sy||fy>ty||a[fx][fy]=='0') continue; 19 dfs(fx,fy); 20 } 21 } 22 inline void BF(){ 23 while(Q--){ 24 memset(v,0,sizeof(v));ans=0; 25 sx=read(),sy=read(),tx=read(),ty=read(); 26 for(int i=sx;i<=tx;i++) 27 for(int j=sy;j<=ty;j++) 28 if(!v[i][j]&&a[i][j]=='1') ans++,dfs(i,j); 29 printf("%d\n",ans); 30 } 31 }int s1[M][M],s2[M][M],s3[M][M]; 32 inline void Solve(){ 33 for(int i=1;i<=n;i++) 34 for(int j=1;j<=m;j++) 35 a[i][j]=(a[i][j]=='1'); 36 for(int i=1;i<=n;i++) 37 for(int j=1;j<=m;j++) 38 s1[i][j]=a[i][j]+s1[i-1][j]+s1[i][j-1]-s1[i-1][j-1], 39 s2[i][j]=(a[i][j]&&a[i+1][j])+s2[i-1][j]+s2[i][j-1]-s2[i-1][j-1], 40 s3[i][j]=(a[i][j]&&a[i][j+1])+s3[i-1][j]+s3[i][j-1]-s3[i-1][j-1]; 41 while(Q--){ 42 sx=read(),sy=read(),tx=read(),ty=read(); 43 int V=s1[tx][ty]-s1[sx-1][ty]-s1[tx][sy-1]+s1[sx-1][sy-1]; 44 int E=s2[tx-1][ty]-s2[tx-1][sy-1]-s2[sx-1][ty]+s2[sx-1][sy-1] 45 +s3[tx][ty-1]-s3[sx-1][ty-1]-s3[tx][sy-1]+s3[sx-1][sy-1]; 46 printf("%d\n",V-E); 47 } 48 49 } 50 int main(){ 51 freopen("wang.in","r",stdin); 52 freopen("wang.out","w",stdout); 53 n=read(),m=read(),Q=read(); 54 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>a[i][j]; 55 // BF(); 56 Solve(); 57 return 0; 58 }