题目连接

https://vjudge.net/contest/397891#problem/B
密码:20201002

解题思路

并查集,半个板子题。
并查集讲解
区别在于,本题并非一条边一条边的join的,而是每次插入一个点,让插入的这个点和已经插入的所有距离满足条件的点join,不满足的只标记插入,但是不进行join。
对于修理电脑操作而言如上。
对于询问两台电脑是否相连,本质上是判断二者是否连通,即根是否相同且必须二者已经插入(其实只要根相同必然是插入的,可以不用判断flag,不过我没试)。

AC代码

#include<iostream>
#include<cmath>
#define ll long long
using namespace std;
const int N=1010;
ll d,n,h[N],z[N],f[N],flag[N];
char op;
int p,q;

void Init(){
    for(int i=1;i<=n;i++) f[i]=i;
}
int find(int x){
    return f[x]==x?x:f[x]=find(f[x]);
}
void join(int x,int y){
    int rx=find(x),ry=find(y);
    if(rx!=ry) f[rx]=ry;
}
double Dis(int i,int j){//求欧几里得距离函数
    return sqrt((h[i]-h[j])*(h[i]-h[j])+(z[i]-z[j])*(z[i]-z[j]));
}
int main(){
    cin>>n>>d;
    Init();
    for(int i=1;i<=n;i++) cin>>h[i]>>z[i];

    while(cin>>op){
        if(op=='O'){
            cin>>p;
            for(int i=1;i<=n;i++){
                if(flag[i]==1 && i!=p && Dis(i,p)<=d) join(i,p);
            }
            flag[p]=1;
        }
        else{
            cin>>p>>q;
            if(find(p)==find(q) && flag[p]==1 && flag[q]==1) cout<<"SUCCESS"<<endl;
            else cout<<"FAIL"<<endl; 
        }
    }
}