NOI2016 网格

题面
答案显然在 − 1 , 0 , 1 , 2 -1,0,1,2 1,0,1,2之中,因为如果不是 − 1 , 0 , 1 -1,0,1 1,0,1的话一定可以在一个角落的位置放两个蛐蛐达成目的。
若答案为 − 1 -1 1,则跳蚤数量小于 2 2 2或者两个跳蚤不相邻。
若答案不为 − 1 -1 1,则将相邻的跳蚤连边,若图不连通则答案为 0 0 0,若图连通且存在割点则答案为 1 1 1,否则答案为 2 2 2
实际上跳蚤数量很多,直接连边不现实。将所有蛐蛐周围的八个跳蚤取出,并取出其所在行、所在列最靠边的四个跳蚤,再在整个矩形的四个角每个角取出四个跳蚤。把取出的跳蚤作为关键跳蚤,关键跳蚤在同一行或同一列且中间没有蛐蛐或其他跳蚤就连边,可以建出点数、边数与蛐蛐数量同阶的等效图。
时间复杂度 O ( ∑ c log ⁡ 2 c ) O(\sum c \log_2c) O(clog2c),空间复杂度 O ( c ) O(c) O(c)

#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
#define R register int
#define I inline
#define N 1300020
int cx[100000],cy[100000],cid[100000],dfn[N],low[N],px[N],py[N],lf[N],pid[N],ct;
vector<int>G[N];
bool in[N];
I bool CompareCX(int x,int y){
	if(cx[x]==cx[y]){
		return cy[x]<cy[y];
	}
	return cx[x]<cx[y];
}
I bool CompareCY(int x,int y){
	if(cy[x]==cy[y]){
		return cx[x]<cx[y];
	}
	return cy[x]<cy[y];
}
I bool ComparePX(int x,int y){
	if(px[x]==px[y]){
		return py[x]<py[y];
	}
	return px[x]<px[y];
}
I bool ComparePY(int x,int y){
	if(py[x]==py[y]){
		return px[x]<px[y];
	}
	return py[x]<py[y];
}
I void Insert(int x,int y,int r,const int n,const int m){
	for(R i=-r;i<=r;i++){
		for(R j=-r;j<=r;j++){
			if(x>-i&&x+i<=n&&y>-j&&y+j<=m){
				px[ct]=x+i;
				py[ct]=y+j;
				pid[ct]=ct;
				ct++;
			}
		}
	}
}
I void Link(int x,int y){
	G[x].push_back(y);
	G[y].push_back(x);
}
I void Tarjan(int x,int F,int&tot,bool&tag){
	in[x]=true;
	ct++;
	dfn[x]=low[x]=ct;
	tot++;
	int cur=0;
	for(auto T:G[x]){
		if(dfn[T]==0){
			Tarjan(T,x,tot,tag);
			if(low[T]<low[x]){
				low[x]=low[T];
			}
			if(low[T]>=dfn[x]){
				cur++;
			}
		}else if(T!=F&&in[T]==true&&dfn[T]<low[x]){
			low[x]=dfn[T];
		}
	}
	in[x]=false;
	if(cur>1||F!=-1&&cur>0){
		tag=true;
	}
}
I void Solve(){
	ct=0;
	int n,m,c,t=0,q=0,x,y;
	scanf("%d%d%d",&n,&m,&c);
	Insert(1,1,1,n,m);
	Insert(1,m,1,n,m);
	Insert(n,1,1,n,m);
	Insert(n,m,1,n,m);
	for(R i=0;i!=c;i++){
		scanf("%d%d",cx+i,cy+i);
		cid[i]=i;
		Insert(cx[i],cy[i],1,n,m);
		Insert(cx[i],1,0,n,m);
		Insert(cx[i],m,0,n,m);
		Insert(1,cy[i],0,n,m);
		Insert(n,cy[i],0,n,m);
	}
	sort(cid,cid+c,CompareCX);
	sort(pid,pid+ct,ComparePX);
	for(R i=0;i!=ct;i++){
		x=px[pid[i]];
		y=py[pid[i]];
		if(q==0||px[pid[q-1]]!=x||py[pid[q-1]]!=y){
			while(t!=c&&(cx[cid[t]]<x||cx[cid[t]]==x&&cy[cid[t]]<y)){
				t++;
			}
			if(t==c||cx[cid[t]]!=px[pid[i]]||cy[cid[t]]!=py[pid[i]]){
				pid[q]=pid[i];
				lf[q]=t;
				q++;
			}
		}
	}
	for(R i=0;i!=q;i++){
		G[pid[i]].clear();
		dfn[pid[i]]=0;
	}
	if(q<2){
		puts("-1");
		return;
	}
	for(R i=1;i!=q;i++){
		int l=lf[i-1];
		if(px[pid[i-1]]==px[pid[i]]&&(l==c||cx[cid[l]]>px[pid[i]]||cx[cid[l]]==px[pid[i]]&&cy[cid[l]]>py[pid[i]])){
			Link(pid[i-1],pid[i]);
		}
	}
	sort(pid,pid+q,ComparePY);
	sort(cid,cid+c,CompareCY);
	t=0;
	for(R i=0;i!=q;i++){
		x=px[pid[i]];
		y=py[pid[i]];
		while(t!=c&&(cy[cid[t]]<y||cy[cid[t]]==y&&cx[cid[t]]<x)){
			t++;
		}
		lf[i]=t;
	}
	for(R i=1;i!=q;i++){
		int l=lf[i-1];
		if(py[pid[i-1]]==py[pid[i]]&&(l==c||cy[cid[l]]>py[pid[i]]||cy[cid[l]]==py[pid[i]]&&cx[cid[l]]>px[pid[i]])){
			Link(pid[i-1],pid[i]);
		}
	}
	t=ct=0;
	bool tag=false;
	Tarjan(pid[0],-1,t,tag);
	if(t!=q){
		puts("0");
	}else if(q==2&&G[pid[0]].empty()==false){
		puts("-1");
	}else if(tag==true){
		puts("1");
	}else{
		puts("2");
	}
}
int main(){
	int t;
	scanf("%d",&t);
	for(R i=0;i!=t;i++){
		Solve();
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值