• Nowcodercontest5278 J 能到达吗


    Nowcodercontest5278 J 能到达吗

    分析:暴力并查集统计联通块,但是要把图分成\(O(k)\)个整齐的矩形,然后考虑相邻的进行合并

    分离矩形:

    对于每个黑点按照\((x,y)\)递增排序,把出现黑点的每一行分成\(k+1\)段矩形,行宽为1

    没有出现黑点的,找到两边最远的空白区域\(x1,x2\),列宽就是\(m\)

    合并矩形:

    得到\(O(k)\)个矩形之后,可以看到矩形的\(x1,x2\)都是对齐分成几段的,对于每个相邻的\(x1,x2\)\(x3,x4\),把所有相邻的\(y\)合并,可以尺取找相邻,并查集合并

    总复杂度就是\(O(k\log k+k\cdot \alpha(k))\)

    const int N=3e6+10,P=1e9+7;
    
    int n,m,k;
    struct Point{//黑点
    	int x,y;
    	bool operator < (const Point __) const {
    		return x<__.x || (x==__.x && y<__.y);
    	}
    }A[N];
    
    struct Rec{// 矩形
    	int lx,rx,ly,ry;
    }B[N];
    int cnt;
    int fa[N];
    ll sz[N];
    int Find(int x){ return fa[x]==x?x:fa[x]=Find(fa[x]); }
    void Union(int x,int y) {
    	x=Find(x),y=Find(y);
    	if(x==y) return;
    	sz[x]+=sz[y],fa[y]=x;
    }
    
    int L[N],R[N],fc;
    
    int Check(Rec a,Rec b){
    	if(a.ly>b.ly) swap(a,b);
    	return a.ry>=b.ly;
    } // 检测是否相交
    
    
    int main() {
    	rep(kase,1,rd()) {
    		n=rd(),m=rd(),k=rd();
    		if(!k) {
    			ll ans=1ll*n*m%P;
    			ans=(ans*(ans-1)/2+ans)%P;
    			printf("%lld\n",ans);
    			continue;
    		}
    		rep(i,1,k) A[i].x=rd(),A[i].y=rd();
    		sort(A+1,A+k+1),cnt=0;
    		if(A[1].x>1) B[++cnt]=(Rec){1,A[1].x-1,1,m};
    		rep(i,1,k) {
    			int j=i;
    			while(j<k && A[j+1].x==A[j].x) ++j;
    			if(A[i].y>1) B[++cnt]=(Rec){A[i].x,A[i].x,1,A[i].y-1};
    			rep(d,i+1,j) if(A[d].y-1>A[d-1].y+1) B[++cnt]=(Rec){A[i].x,A[i].x,A[d-1].y+1,A[d].y-1};
    			if(A[j].y<m) B[++cnt]=(Rec){A[i].x,A[i].x,A[j].y+1,m}; // 切成k+1段
    			i=j;
    			if(i<k && A[i+1].x>A[i].x+1) B[++cnt]=(Rec){A[i].x+1,A[i+1].x-1,1,m};// 没有出现黑点的位置
    		}
    		if(A[k].x<n) B[++cnt]=(Rec){A[k].x+1,n,1,m};// 没有
    
    		rep(i,1,cnt) sz[i]=1ll*(B[i].rx-B[i].lx+1)*(B[i].ry-B[i].ly+1),fa[i]=i; // 预处理并查集
    
    		fc=0;
    		rep(i,1,cnt) {
    			int j=i;
    			while(j<cnt && B[j+1].lx==B[j].lx && B[j+1].rx==B[j].rx) ++j;
    			L[++fc]=i,R[fc]=j;
    			i=j;
    		}//每一层的x1,x2切开
    		rep(i,1,fc-1) {
    			if(B[i].rx<B[i+1].lx-1) continue;
    			int p=L[i];
    			rep(j,L[i+1],R[i+1]) {
    				while(p<R[i] && B[p+1].ry<=B[j].ry) {
    					if(Check(B[j],B[p])) Union(j,p);
    					++p;
    				}
    				if(Check(B[j],B[p])) Union(j,p);
    				if(p<R[i] && Check(B[j],B[p+1])) Union(j,p+1);
    			}
    		}//相邻层合并,p是尺取指针
    		ll ans=0;
    		rep(i,1,cnt) if(Find(i)==i) {
    			sz[i]%=P;
    			ans=(ans+sz[i]*(sz[i]-1)/2+sz[i])%P;
    		}
    		ans=(ans%P+P)%P;
    		printf("%lld\n",ans);
    	}
    }
    
    
    
  • 相关阅读:
    .dbmdl 文件
    where 命令一个快速定位工具所在的功能
    Window 2008 R2 软件限制策略的默认调整,导致记录事件日志的权限不足
    大家知道什么是 asp.net 呢 ?学习一下
    asp.net membership常见问题总结
    DivCSS布局实例:很实用的图文混排CSS列表
    js 在网页里让文本框只能输入数字的一种方法,外加回车换Tab
    从零开始学DedeCms模板,模板教程,从此模板制作不求人
    .net 数据类型
    常用正则表达式
  • 原文地址:https://www.cnblogs.com/chasedeath/p/12727428.html
Copyright © 2020-2023  润新知