Use this to learn the idea, then write your own version.
12 3 4class UnionFind:5 '''Represents a data structure that tracks a set of elements partitioned6 into a number of disjoint (non-overlapping) subsets.7 Landau notation: O(α(n)), where α(n) is the inverse Ackermann function.8 See:9 https:www.youtube.com/watch?v=zV3Ul2pA2Fw10 https:en.wikipedia.org/wiki/Disjoint-set_data_structure11 https:atcoder.jp/contests/abc120/submissions/444494212 '''13 14 def __init__(self, number_count: int):15 '''16 Args:17 number_count: The size of elements (greater than 2).18 '''19 self.parent_numbers = [-1 for _ in range(number_count)]20 21 def find_root(self, number: int) -> int:22 '''Follows the chain of parent pointers from number up the tree until23 it reaches a root element, whose parent is itself.24 Args:25 number: The trees id (0-index).26 Returns:27 The index of a root element.28 '''29 if self.parent_numbers[number] < 0:30 return number31 32 self.parent_numbers[number] = self.find_root(self.parent_numbers[number])33 return self.parent_numbers[number]34 35 def get_group_size(self, number: int) -> int:36 '''37 Args:38 number: The trees id (0-index).39 Returns:40 The size of group.41 '''42 return -self.parent_numbers[self.find_root(number)]43 44 def is_same_group(self, number_x: int, number_y: int) -> bool:45 '''Represents the roots of tree number_x and number_y are in the same46 group.47 Args:48 number_x: The trees x (0-index).49 number_y: The trees y (0-index).50 '''51 return self.find_root(number_x) == self.find_root(number_y)52 53 def merge_if_needs(self, number_x: int, number_y: int) -> bool:54 '''Uses find_root to determine the roots of the tree number_x and55 number_y belong to. If the roots are distinct, the trees are combined56 by attaching the roots of one to the root of the other.57 Args:58 number_x: The trees x (0-index).59 number_y: The trees y (0-index).60 '''61 x = self.find_root(number_x)62 y = self.find_root(number_y)63 64 if x == y:65 return False66 67 if self.get_group_size(x) >= self.get_group_size(y):68 self.parent_numbers[x] += self.parent_numbers[y]69 self.parent_numbers[y] = x70 else:71 self.parent_numbers[y] += self.parent_numbers[x]72 self.parent_numbers[x] = y73 return True74 75 76def is_on_circle(xi, yi, ri, x, y):77 if (x - xi) ** 2 + (y - yi) ** 2 == ri ** 2:78 return True79 else:80 return False81 82 83def is_hit(xi, yi, ri, xj, yj, rj):84 dist = abs(xi - xj) ** 2 + abs(yi - yj) ** 285 86 if (max(ri, rj) - min(ri, rj)) ** 2 <= dist <= (ri + rj) ** 2:87 return True88 else:89 return False90 91 92def main():93 from collections import deque94 import sys95 96 input = sys.stdin.readline97 98 n = int(input())99 sx, sy, tx, ty = map(int, input().split())100 xyr = [tuple(map(int, input().split())) for _ in range(n)]101 cs, ct = -1, -1 102 uf = UnionFind(n)103 104 105 for i in range(n):106 xi, yi, ri = xyr[i]107 108 if is_on_circle(xi, yi, ri, sx, sy):109 cs = i110 if is_on_circle(xi, yi, ri, tx, ty):111 ct = i112 113 114 for i in range(n):115 xi, yi, ri = xyr[i]116 117 for j in range(i + 1, n):118 xj, yj, rj = xyr[j]119 120 if is_hit(xi, yi, ri, xj, yj, rj):121 uf.merge_if_needs(i, j)122 123 if uf.is_same_group(cs, ct):124 print("Yes")125 else:126 print("No")127 128 129if __name__ == "__main__":130 main()131