• 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;
    }
    
  • 相关阅读:
    数据库的视图概念作用
    常见的反爬虫和应对方法
    referrer policy
    JSON
    异步消息处理机制
    Acitivity(活动)
    springboot @Autowired 空指针异常问题处理
    CentOS7 宝塔 ThinkPHP SQLServer 2000 安装FreeTDS
    PHP THINKPHP 函数 dump var_dump var_export
    ThinkPHP5 WHERE AND OR 实现多条件查询
  • 原文地址:https://www.cnblogs.com/Kelvin2005/p/15163713.html
Copyright © 2020-2023  润新知