• [NOI2016] 网格


    XXXVIII.[NOI2016] 网格

    首先,答案一定 \(\leq2\),因为四个角的跳蚤被围住只需要两个蛐蛐,而如果蛐蛐占住了一个角又会产生新的角。

    \(-1\) 的情形比较容易,要么空隙少于 \(2\) 个,要么仅剩的两个空隙在一起。两种情况下 \(n\times m\) 都与 \(c\) 同级别,因此可以暴力。

    \(0\) 的情形等价于存在不连通的部分。可以发现,蛐蛐形成的八连通块,找到块中所有节点周边八个跳蚤并跑跳蚤的四联通性。若发现八连通块周边的跳蚤属于两个及以上不同的连通块,则即为 \(0\)

    \(1\) 的情形等价于存在割点。割点有两种可能,一是 \(n,m\) 中至少有一个为 \(1\),二是蛐蛐把跳蚤分出了割点。假如依旧只找周边 \(8\) 个跳蚤跑割点的话,那周边一圈的节点可能会被当成割点,比如这个样例,其中 # 代表蛐蛐。

    ...
    ...
    ..#
    ...
    ...
    

    但是我们发现,只需要选取周边两圈的节点即可规避上述问题。但是,需要注意的是,割点只能统计周边一圈的节点,否则会被

    #....
    .....
    .....
    .....
    ....#
    

    这组样例干掉——正中央的那个节点是割点,但不是内圈割点,因此不能计入。

    然后剩余的情景即为 \(2\)

    需要注意的是,本题数据范围很大,存图要么用 unordered_map,要么手写哈希表。这里试了试哈希表,还挺好写的。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int M=3001000;
    int T,n,m,c,dx[4]={1,0,-1,0},dy[4]={0,1,0,-1},X[100100],Y[100100];
    const int P=4999999;
    const int HT=5000000;
    const int BS=1e9+7;
    struct HashTable{
    	int head[HT],val[HT],nxt[HT],rx[HT],ry[HT],cnt;
    	int HASH(int x,int y){return (1ll*x*m+y)%P;}
    	void clear(){memset(head,-1,sizeof(head));}
    	void ins(int x,int y,int z){
    		int p=HASH(x,y);
    		nxt[cnt]=head[p],val[cnt]=z,rx[cnt]=x,ry[cnt]=y,head[p]=cnt++;
    	}
    	int fnd(int x,int y){for(int i=head[HASH(x,y)];i!=-1;i=nxt[i])if(rx[i]==x&&ry[i]==y)return val[i];return -1;}
    }m1,m2;
    bool checkimp(){//the function for impossibility check.
    	if(1ll*n*m-c<2)return true;
    	if(1ll*n*m-c>2)return false;
    	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
    		if(m1.fnd(i,j)!=-1)continue;
    		for(int k=0;k<4;k++){
    			int I=i+dx[k],J=j+dy[k];
    			if(!I||!J||I>n||J>m||m1.fnd(I,J)!=-1)continue; 
    			return true;
    		}
    	}
    	return false;
    }
    int cnt,bcm,cid[100100],dsu[100100];
    pair<int,int>p[M];
    vector<int>v[M];
    int blk[M];
    void floodfill(int x){
    	blk[x]=bcm;
    	for(auto y:v[x])if(!blk[y])floodfill(y);
    }
    int find(int x){return dsu[x]==x?x:dsu[x]=find(dsu[x]);}
    void merge(int x,int y){x=find(x),y=find(y);if(x!=y)dsu[y]=x;}
    bool checkdisc(){//check if the graph is disconnected.
    	for(int i=1;i<=cnt;i++)if(!blk[i])bcm++,floodfill(i);
    	for(int i=1;i<=c;i++)dsu[i]=i,cid[i]=0;
    	for(int i=1;i<=c;i++)for(int j=-1;j<=1;j++)for(int k=-1;k<=1;k++){
    		if(!j&&!k||X[i]+j<1||Y[i]+k<1||X[i]+j>n||Y[i]+k>m)continue;
    		int tmp=m1.fnd(X[i]+j,Y[i]+k);
    		if(tmp!=-1)merge(i,tmp);
    	}
    	for(int i=1;i<=c;i++)for(int j=0;j<4;j++){
    		int x=X[i]+dx[j],y=Y[i]+dy[j];
    		int id=m2.fnd(x,y);if(id==-1)continue;
    		if(!cid[find(i)])cid[find(i)]=blk[id];
    		else if(cid[find(i)]!=blk[id])return true;
    	}
    	return false;
    }
    int dfn[M],low[M],tot,cut;
    bool fir[M];
    void Tarjan(int x,bool rt){
    	dfn[x]=low[x]=++tot;
    	int son=0;
    	for(auto y:v[x]){
    		if(!dfn[y])son++,Tarjan(y,false),low[x]=min(low[x],low[y]),cut+=(!rt&&dfn[x]<=low[y]&&fir[x]);
    		else low[x]=min(low[x],dfn[y]);
    	}
    	if(rt&&son>=2&&fir[x])cut++;
    }
    bool checkcut(){
    	if(n==1||m==1)return true;
    	for(int i=1;i<=cnt;i++)if(!dfn[i])Tarjan(i,true);
    	return cut>=1;
    }
    void read(int &x){
    	x=0;
    	char c=getchar();
    	while(c>'9'||c<'0')c=getchar();
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    }
    int mian(){
    	read(n),read(m),read(c);
    	m1.clear(),m2.clear();
    	for(int i=1;i<=cnt;i++)dfn[i]=low[i]=blk[i]=0,v[i].clear();cnt=tot=cut=bcm=0;
    	for(int i=1,x,y;i<=c;i++)read(X[i]),read(Y[i]),m1.ins(X[i],Y[i],i);
    	if(checkimp())return -1;
    	for(int i=1;i<=c;i++)for(int j=-2;j<=2;j++)for(int k=-2;k<=2;k++){
    		int x=X[i]+j,y=Y[i]+k;
    		if(x<1||y<1||x>n||y>m||m1.fnd(x,y)!=-1)continue;
    		int tmp=m2.fnd(x,y);
    		if(tmp!=-1){fir[tmp]|=(abs(j)<=1&&abs(k)<=1);continue;}
    		m2.ins(x,y,++cnt),p[cnt]=make_pair(x,y);
    		fir[cnt]=(abs(j)<=1&&abs(k)<=1);
    	}
    	for(int i=1;i<=cnt;i++)for(int j=0;j<4;j++){
    		int x=p[i].first+dx[j],y=p[i].second+dy[j];
    		int tmp=m2.fnd(x,y);
    		if(tmp!=-1)v[i].push_back(tmp);
    	}
    	if(checkdisc())return 0;
    	if(checkcut())return 1;
    	return 2;
    }
    int main(){
    //	freopen("P1173_1.in","r",stdin); 
    	scanf("%d",&T);
    	while(T--)printf("%d\n",mian());
    	return 0;
    }
    

  • 相关阅读:
    SQL Server 2008 如何查看与创建约束
    Hibernate的主键生成策略
    sql server的id字段设置为自动生成的,那么该怎么写insert语句呢?
    org.hibernate.AnnotationException: Collection has neither generic type or OneToMany.targetEntity() defined: com.bjsxt.model.Student.courses
    INSERT 语句与 FOREIGN KEY 约束"XXX"冲突。该冲突发生于数据库"XXX",表"XXX", column 'XXX。
    在排序数组中查找符合条件的数
    求二叉树中节点的最大距离
    设计包含min 函数的栈
    寻找链表的倒数第K个节点
    翻转句子中单词的顺序
  • 原文地址:https://www.cnblogs.com/Troverld/p/14612760.html
Copyright © 2020-2023  润新知