Jerry只是一只小老鼠,他不懂并查集,他只知道搜索......
我们假设Jerry有着超强的运动能力,它能够爬遍每个奶酪空洞,除非它已经到达了奶酪顶部。于是,我们可以先把所有的奶酪底部的空洞找出来,再从这些空洞开始广度优先搜索,直到搜到顶部的空洞为止。既然空间内两点距离可以求出,两个空洞是否相连就是两个空洞的中心点距离是否不大于空洞直径。脑力不行的Jerry已经等不及了,我们开始干吧!

#define MAXN 1001 // 最大空洞数量

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>

using namespace std;

class Cavity // 空洞类
{
public:
    long long x; // x坐标
    long long y; // y坐标
    long long z; // z坐标
};

int t;                       // 测试数据总数
int n;                       // 空洞数量
int h;                       // 奶酪高度
int r;                       // 空洞半径
int numLowerSurfaceCavities; // 下表面空洞数量

Cavity cavities[MAXN];             // 所有空洞
Cavity lowerSurfaceCavities[MAXN]; // 下表面的空洞
Cavity cavitiesHaveGone[MAXN];     // 经过的空洞

bool ifHaveGoneCavity[MAXN]; // 是否去过该空洞
bool ifCanGetTop;            // 能否到达顶部

double DistanceBetwinCavities (Cavity, Cavity);
void   GoFromCavity           (Cavity);
void   Init                   ();

int main(int argc, char const *argv[])
{
    scanf("%d", &t); // 输入t
    while (t--)      // 开始循环
    {
        Init();                        // 初始化
        scanf("%d %d %d", &n, &h, &r); // 输入n、h、r
        for (int i = 1; i <= n; i++)
        {
             // 输入各个空洞的坐标
            scanf("%lld %lld %lld", &cavities[i].x, &cavities[i].y, &cavities[i].z);
            if (cavities[i].z <= r) // 如果是下表面的空洞
            {
                 // 记录到 lowerSurfaceCavities 数组中
                lowerSurfaceCavities[++numLowerSurfaceCavities] = cavities[i];
            }
        }
        for (int i = 1; i <= numLowerSurfaceCavities; i++) // 枚举下表面的空洞
        {
            if (!ifCanGetTop) // 如果还不能到达顶部
            {
                 // 把经过的空洞的记录清空
                memset(ifHaveGoneCavity, false, sizeof(ifHaveGoneCavity));
                 // Jerry从这个空洞出发,开始BFS
                GoFromCavity(lowerSurfaceCavities[i]);
            }
            else // 已经证明可以到达顶部
            {
                break; // 直接退出
            }
        }
        if (ifCanGetTop) // 能到达顶部
        {
            printf("Yes\n"); // 输出 Yes
        }
        else // 不能到达
        {
            printf("No\n"); // 输出 No
        }
    }
    return 0;
}
 // 空洞之间的距离
double DistanceBetwinCavities(Cavity cavity1, Cavity cavity2)
{
    return sqrt(pow(cavity1.x - cavity2.x, 2) + pow(cavity1.y - cavity2.y, 2) + pow(cavity1.z - cavity2.z, 2));
}
 // 从空洞出发
void GoFromCavity(Cavity startCavity)
{
    int head = 0; // 队列头指针
    int tail = 1; // 队列尾指针

    cavitiesHaveGone[1] = startCavity; // 起点空洞先入队,Jerry走到起点

    do // Jerry开始往上爬
    {
        head++; // 头指针后移一位,指向要扩展的空洞(即下一步从该空洞出发)
        for (int i = 1; i <= n; i++) // 枚举所有的空洞
        {
             // 如果有空洞可以到达且该空洞没有到过(去过没到达顶部就不用去两回了)
            if (DistanceBetwinCavities(cavitiesHaveGone[head], cavities[i]) <= 2 * r && !ifHaveGoneCavity[i])
            {
                cavitiesHaveGone[++tail] = cavities[i]; // Jerry爬到该空洞
                ifHaveGoneCavity[i]      = true;        // 已经来过这个空洞了
                if (cavitiesHaveGone[tail].z + r >= h)  // 如果这个空洞是奶酪上表面的空洞(Jerry已经到了OvO)
                {
                    ifCanGetTop = true; // Jerry到达顶部了
                    return;             // 那还要继续爬吗?
                }
            }
        }
    } while (head < tail); // 一定要有恒心,只要没到达顶部,能爬多少就爬多少
}
 // 初始化
void Init()
{
    numLowerSurfaceCavities = 0;
    ifCanGetTop             = false;
}

Jerry认为我帮了他一个大忙,很感激我,为我点了个赞,那你呢?