beats 96% memory wise :)
\n\n# Code\n\nclass UnionFind:\n    def __init__(self, n):\n        self.parent = list(range(n))\n        \n    def find_parent(self, p):\n        if self.paren
\n\n# Code\n```\nclass UnionFind:\n    def __init__(self, n):\n        self.parent = list(range(n))\n        \n    def find_parent(self, p):\n        if self.parent[p] != p:\n            self.parent[p] = self.find_parent(self.parent[p])\n        return self.parent[p]\n    \n    def union_sets(self, u, v):\n        pu, pv = self.find_parent(u), self.find_parent(v)\n        self.parent[pu] = pv\n\nclass Solution:\n    def findCriticalAndPseudoCriticalEdges(self, n: int, edges: List[List[int]]) -> List[List[int]]:\n        def find_MST(graph, block, e):\n            uf = UnionFind(n)\n            weight = 0\n            \n            if e != -1:\n                weight += edges[e][2]\n                uf.union_sets(edges[e][0], edges[e][1])\n            \n            for i in range(len(edges)):\n                if i == block:\n                    continue\n                \n                if uf.find_parent(edges[i][0]) == uf.find_parent(edges[i][1]):\n                    continue\n                \n                uf.union_sets(edges[i][0], edges[i][1])\n                weight += edges[i][2]\n            \n            for i in range(n):\n                if uf.find_parent(i) != uf.find_parent(0):\n                    return float(\'inf\')\n            \n            return weight\n        \n        critical = []\n        pseudo_critical = []\n        \n        for i, edge in enumerate(edges):\n            edge.append(i)\n        \n        edges.sort(key=lambda x: x[2])\n        mst_weight = find_MST(edges, -1, -1)\n        \n        for i, edge in enumerate(edges):\n            if mst_weight < find_MST(edges, i, -1):\n                critical.append(edge[3])\n            elif mst_weight == find_MST(edges, -1, i):\n                pseudo_critical.append(edge[3])\n        \n        return [critical, pseudo_critical]\n```
['Python3']