[python] Union find *can* work but not in the way your thinking
Intuition\nIn order to understand the following I assume you have a strong grasp of union find and the default solution to this problem. \n\nWhy doesnt vanilla 
# Intuition\nIn order to understand the following I assume you have a strong grasp of union find and the default solution to this problem. \n\nWhy doesnt vanilla union find work here? Because edges can be directional or bidirectional in this problem. \ni.e If the graph had all bi-directional edges union find would work fine.\n\nBut can we gain some perf by labeling the bidirectional clusters if they exist? \nyes! \n\ni.e \n\nwe use the parent labels to prune our search.\nif we traverse a single node from a connected cluster, there is no    point in traversing another node from within that cluster. \n\nIn addition, if we have a bomb chain,\nWe always want to start from the "root" when traversing if possible\nand not re-traverse any child nodes further down the chain. \n\n# Code\n```\nfrom collections import defaultdict \n\nclass Solution:\n    def maximumDetonation(self, bombs: List[List[int]]) -> int:\n        def is_connected(p1, p2):\n            p1x, p1y, p1r = p1\n            p2x, p2y, p2r = p2 \n            return p1r ** 2 >= (p2y - p1y)**2 + (p2x - p1x)**2\n        \n        def find(node):\n            while node != parent[node]:\n                parent[node] = parent[parent[node]]\n                node = parent[node]\n            return node \n\n        \n        def union(a, b):\n            pa, pb = find(a), find(b)\n            if pa == pb:\n                return \n            if rank[pa] > rank[pb]:\n                rank[pa] += rank[pb]\n                parent[pb] = pa \n            else:\n                rank[pb] += rank[pa]\n                parent[pa] = pb \n        \n        def iter_search(root):\n            stack = [root]\n            visited = set(stack)\n            while stack:\n                for next_node in graph[stack.pop()]:\n                    if next_node in visited: continue \n                    visited.add(next_node)\n                    stack.append(next_node)\n            return len(visited) \n\n        parent = list(range(len(bombs)))\n        rank = [1] * len(bombs)\n\n        graph = defaultdict(list)\n        visited = set() \n        is_child = set() \n\n        for i in range(len(bombs)):\n            for j in range(len(bombs)):\n                if i == j: continue \n                if is_connected(bombs[i], bombs[j]):\n                    graph[i].append(j)\n                    if is_connected(bombs[j], bombs[i]):\n                        # Amortized O(1) op\n                        union(i, j)\n                    else:\n                        # optimization:\n                        # dont traverse from child nodes\n                        # if its directional\n                        is_child.add(j)\n\n\n\n\n        maxv = 0 \n        for node in range(len(bombs)):\n            if parent[node] in visited or node in is_child:\n                continue \n            maxv = max(maxv, iter_search(node))\n            visited.add(parent[node])\n        return maxv \n\n```
['Union Find', 'Graph', 'Biconnected Component', 'Strongly Connected Component', 'Python3']