【并查集】Baltic2016 Park

分析:

很简单的并查集水题。
每个圆视为一个点,上下左右四个边界各视为一个点,

两点间距离表示:最大能穿过的圆的直径。

所以可以先把 n 2 n^2 n2条边的预处理出来,然后再把边权从小到大排序,询问的圆也从小到大排序即可。

判断一下几个边界是否连通,就能知道它能到达哪些点。

只不过卡精度了很难受。。。

所以得用longlong二分适合的边权。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#define SF scanf
#define PF printf
#define MAXN 3000010
#define EPS 1e-6
using namespace std;
typedef long long ll;
int fa[MAXN];
struct node{
	int u,v;
	ll val;
	node () {}
	node (int u1,int v1,double val1):u(u1),v(v1),val(val1) {}
	bool operator <(const node &a) const {
		if(val!=a.val)
			return val<a.val;	
		if(u!=a.u)
			return u<a.u;
		return v<a.v;
	}
}edge[MAXN];
struct cir{
	int x,y,r;
	bool operator <(const cir &a) const {
		if(r!=a.r)
			return r<a.r;
		if(x!=a.x)
			return x<a.x;
		return y<a.y;
	}
}p[MAXN],q[MAXN];
int get_fa(int x){
	if(fa[x]==0)
		return x;
	fa[x]=get_fa(fa[x]);
	return fa[x];	
}
void merge(int u,int v){
	u=get_fa(u);
	v=get_fa(v);
	if(u==v)
		return ;
	fa[u]=v;
}
bool check(int u,int v){
	u=get_fa(u);
	v=get_fa(v);
	return u!=v;
}
bool check(int u,int v,ll len){
	ll dx=p[u].x-p[v].x;
	ll dy=p[u].y-p[v].y;
	ll len1=dx*dx+dy*dy;
	len=len+p[u].r+p[v].r;
	return len1<len*len;
}
int n,m,w,h,tot;
ll find_dist(int u,int v){
	ll l=0,r=max(w,h);
	ll ans=r;
	while(l!=r){
		ll mid=(l+r)>>1;
		if(check(u,v,mid)){
			r=mid;
		}
		else
			l=mid+1;
	}
	return l;
}
string ans[MAXN];
int main(){
	SF("%d%d",&n,&m);
	SF("%d%d",&w,&h);
	for(int i=1;i<=n;i++)
		SF("%d%d%d",&p[i].x,&p[i].y,&p[i].r);	
	for(int i=1;i<=m;i++){
		SF("%d%d",&q[i].r,&q[i].x);
		q[i].y=i;
	}
	int L=n+1,D=n+2,R=n+3,U=n+4;
	for(int i=1;i<=n;i++){
		edge[++tot]=node(i,L,p[i].x-p[i].r);
		edge[++tot]=node(i,D,p[i].y-p[i].r);
		edge[++tot]=node(i,R,w-p[i].x-p[i].r);
		edge[++tot]=node(i,U,h-p[i].y-p[i].r);
		for(int j=i+1;j<=n;j++)
			edge[++tot]=node(i,j,find_dist(i,j));
	}
	sort(edge+1,edge+1+tot);
	sort(q+1,q+1+m);
	int top=1;
	for(int i=1;i<=m;i++){
		while(top<=tot&&edge[top].val <=2ll*q[i].r){
//			PF("{%d %d %lf}\n",edge[top].u,edge[top].v,edge[top].val);
			merge(edge[top].u,edge[top].v);
			top++;
		}
//		PF("[%d %d %d %d]\n",i,q[i].x,q[i].r,q[i].y);
		int id=q[i].x;
		if(id==1){
			ans[q[i].y]+='1';
			if(check(D,R)&&check(D,U)&&check(L,D))
				ans[q[i].y]+='2';
			if(check(U,R)&&check(L,R)&&check(U,D)&&check(L,D))
				ans[q[i].y]+='3';
			if(check(L,U)&&check(L,R)&&check(L,D))
				ans[q[i].y]+='4';
		}
		else if(id==2){
			if(check(D,R)&&check(D,U)&&check(L,D))
				ans[q[i].y]+='1';
			ans[q[i].y]+='2';
			if(check(D,R)&&check(L,R)&&check(U,R))
				ans[q[i].y]+='3';
			if(check(L,U)&&check(L,R)&&check(U,D)&&check(D,R))
				ans[q[i].y]+='4';
		}
		else if(id==3){
			if(check(U,R)&&check(L,R)&&check(U,D)&&check(L,D))
				ans[q[i].y]+='1';
			if(check(D,R)&&check(L,R)&&check(U,R))
				ans[q[i].y]+='2';
			ans[q[i].y]+='3';
			if(check(U,R)&&check(U,D)&&check(U,L))
				ans[q[i].y]+='4';
		}
		else if(id==4){
			if(check(L,U)&&check(L,R)&&check(L,D))
				ans[q[i].y]+='1';
			if(check(L,U)&&check(L,R)&&check(U,D)&&check(R,D))
				ans[q[i].y]+='2';
			if(check(U,R)&&check(U,D)&&check(U,L))
				ans[q[i].y]+='3';
			ans[q[i].y]+='4';
		}
	}
	for(int i=1;i<=m;i++)
		cout<<ans[i]<<endl;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值