poj2236——并查集变形

题目链接:http://poj.org/problem?id=2236

An earthquake takes place in Southeast Asia. The ACM (Asia Cooperated Medical team) have set up a wireless network with the lap computers, but an unexpected aftershock attacked, all computers in the network were all broken. The computers are repaired one by one, and the network gradually began to work again. Because of the hardware restricts, each computer can only directly communicate with the computers that are not farther than d meters from it. But every computer can be regarded as the intermediary of the communication between two other computers, that is to say computer A and computer B can communicate if computer A and computer B can communicate directly or there is a computer C that can communicate with both A and B.

In the process of repairing the network, workers can take two kinds of operations at every moment, repairing a computer, or testing if two computers can communicate. Your job is to answer all the testing operations.

Input

The first line contains two integers N and d (1 <= N <= 1001, 0 <= d <= 20000). Here N is the number of computers, which are numbered from 1 to N, and D is the maximum distance two computers can communicate directly. In the next N lines, each contains two integers xi, yi (0 <= xi, yi <= 10000), which is the coordinate of N computers. From the (N+1)-th line to the end of input, there are operations, which are carried out one by one. Each line contains an operation in one of following two formats:
1. "O p" (1 <= p <= N), which means repairing computer p.
2. "S p q" (1 <= p, q <= N), which means testing whether computer p and q can communicate.

The input will not exceed 300000 lines.

Output

For each Testing operation, print "SUCCESS" if the two computers can communicate, or "FAIL" if not.

Sample Input

4 1
0 1
0 2
0 3
0 4
O 1
O 2
O 4
S 1 4
O 3
S 1 4

Sample Output

FAIL
SUCCESS

题目翻译:

鸡山村发生了一次地震。ACM (Asia Cooperated Medical 亚洲联合医疗队) 已经为圣维尔供电中心的电脑搭建了一个无线网络,但受到了一次不可预知的余震攻击,因此网络中的所有电脑都被破坏了。电脑被逐台修复,网络逐步恢复了工作。由于受到硬件的约束,每台电脑只能与距离它不超过 d 米的其它电脑直接通信。但每台电脑可被看作其它两台电脑的通信中转点,也就是说,如果电脑 A 和电脑 B 可以直接通信,或存在一台电脑 C 既可与 A 也可与 B 通信,那么电脑 A 和电脑 B 之间就能够通信。

在处理网络修复的过程中,工作人员们在任何一个时刻,可以执行两种操作:维修一台电脑,或测试两台电脑是否能够通信。请您找出全部的测试操作。

输入

第一行包含了两个整数 N 和 d (1 <= N <= 1001, 0 <= d <= 20000)。此处 N 是电脑的数目,编号从 1 到 N;同时,D 是两台电脑之间能够直接通信的最大距离。接下来的 N 行,每行包含两个整数 xi, yi (0 <= xi, yi <= 10000),表示 N 台电脑的坐标。从第 (N+1) 行到输入结束,是逐一执行的操作,每行包含一个操作,格式是以下两者之一:
1. "O p" (1 <= p <= N),表示维护电脑 p 。
2. "S p q" (1 <= p, q <= N),表示测试电脑 p 和 q 是否能够通信。

输入不超过 300000 行。

输出

对于每个测试操作,如果两台电脑能够通信,则打印 "SUCCESS";否则,打印 "FAIL"。

 

作为kuangbin带你飞并查集专题的第一题,这一题不是特别友好,不过也不是特别难想。

关于并查集的基础知识这里不多赘述,只单单讲这个题的做法。

测试两个电脑之间能否通信不难,只需要判断两个电脑是否同属于一个根节点。

第一次我想的是在每一次询问之前,都对所有电脑进行判断,合并,结果发现会超时。

因此我们可以每维护一个电脑之后,就对这个电脑能到的维护过的电脑进行合并。

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=1005;
struct computer{
    int x,y;
    int flag;
}c[maxn];
int p[maxn];
char s[10];
int n,d;
int Find(int x){
    return p[x]==x?x:p[x]=Find(p[x]);
}
bool judge(int p1,int p2){
    return (c[p1].x-c[p2].x)*(c[p1].x-c[p2].x)+(c[p1].y-c[p2].y)*(c[p1].y-c[p2].y)<=d*d?true:false;
}
int main(int argc, char** argv) {
    while(~scanf("%d%d",&n,&d)){
        for(int i=1;i<=n;++i){
            p[i]=i;
            scanf("%d%d",&c[i].x,&c[i].y);
            c[i].flag=0;
        }
        while(~scanf("%s",s)){
            if(s[0]=='O'){
                int tt;
                scanf("%d",&tt);
                c[tt].flag=1;
                for(int i=1;i<=n;++i){
                    if(c[i].flag&&judge(i,tt)){
                        int xx=Find(i);
                        int yy=Find(tt);
                        if(xx!=yy) p[yy]=xx;
                    }
                }
            }
            else{
                //for(int i=1;i<=n;++i)
                    //printf("%d ",p[i]);
                int tt,rr;
                scanf("%d%d",&tt,&rr);
                int xx=Find(tt);
                int yy=Find(rr);
                if(xx==yy) printf("SUCCESS\n");
                else printf("FAIL\n");
            }
        }
    }
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值