To_Heart—题解——CF33D

首先我们发现,任意两个圆是没有交叉点的。所以说对于任何两个圆,只有包含或者并列的情况,所以就可以转换成一棵树。

#include<bits/stdc++.h>
#define ll long long
using namespace std;

struct zz{
	int u,id;
}T[300005];

struct ss{
	int r;
	int x,y;
}a[1005],s[1005];
 
bool cmp(ss x,ss y){
	return x.r<y.r;
}

ll Dist(ss a,ss b){
	ll x,y,xx,yy;
	x=a.x,y=a.y;
	xx=b.x,yy=b.y;
	return (ll)(x-xx)*(x-xx)+(ll)(y-yy)*(y-yy);
}

int n,m,k;
ll ans=0;
vector<int> v[300005];
void Add(int x,int y){
	v[x].push_back(y);
	v[y].push_back(x);
}
vector<zz> sum[300005];
bool f[300005];
int pre[300005];
ll dist[300005];
int tot[3000005];

void Make_Set(){
	for(int i=1;i<=m;i++){
		pre[i]=i;
	}
}

int Find_Set(int x){
	if(pre[x]!=x)
		pre[x]=Find_Set(pre[x]);
	return pre[x];
}

void DFS(int p,int fa){
	dist[p]=dist[fa]+1;
    for(int i=0;i<v[p].size();i++){
    	int x=v[p][i];
    	if(x!=fa)
			DFS(x,p);
	}
}

void Tarjan(int x){
	f[x]=1;
	for(int i=0;i<v[x].size();i++){
		int y=v[x][i];
		if(f[y])
			continue;
		Tarjan(y);
		pre[y]=Find_Set(x);
	}
	for(int i=0;i<sum[x].size();i++){
		zz now=sum[x][i];
		if(!f[now.u])
			continue;
		tot[now.id]=Find_Set(now.u);
	}
}

int main(){
	cin>>n>>m>>k;
	Make_Set();
	for(int i=1;i<=n;i++){
		scanf("%d%d",&a[i].x,&a[i].y);
	}
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&s[i].r,&s[i].x,&s[i].y);
	}
	s[0]=(ss){2147483600,0,0};
	sort(s,s+m+1,cmp);
	
	for(int i=1;i<=n;i++){
		for(int j=0;j<=m;j++){
			if(Dist(a[i],s[j])<=(ll)s[j].r*(ll)s[j].r){
				a[i].r=j;
				break;
			}
		}
	}
	
	for(int i=0;i<=m;i++){
    	for(int j=i+1;j<=m;j++)
    		if(Dist(s[i],s[j])<(ll)s[j].r*s[j].r){
				Add(i,j);
				break;
			}
    }
	DFS(0,0);
	for(int i=1;i<=k;i++){
		int x,y;
		scanf("%d %d",&x,&y);
		x=a[x].r;y=a[y].r;
		sum[x].push_back({y,i});
		sum[y].push_back({x,i});
		T[i].id=x;T[i].u=y;
	}
	Tarjan(0);
	for(int i=1;i<=k;i++){
		int x=T[i].id,y=T[i].u;
		cout<<abs(dist[x]+dist[y]-2*dist[tot[i]])<<endl;
	}
	return 0;
}

posted @ 2021-01-16 08:13  To_Heart  阅读(36)  评论(0)    收藏  举报