Accepted C# Solution. Kruskal's algo.
\n     public class Solution\n    {\n        public class Unions\n        {\n            private readonly int[] _parents;\n            private readonly int[] _r
```\n     public class Solution\n    {\n        public class Unions\n        {\n            private readonly int[] _parents;\n            private readonly int[] _ranks;\n\n            public Unions(int n)\n            {\n                _parents = new int[n];\n                _ranks = new int[n];\n                for (int i = 0; i < n; i++)\n                {\n                    _parents[i] = i;\n                }\n            }\n\n            public int Find(int x)\n            {\n                if (x != _parents[x])\n                {\n                    x = Find(_parents[x]);\n                }\n                return _parents[x];\n            }\n\n            public bool Union(int x, int y)\n            {\n                int px = Find(x);\n                int py = Find(y);\n                if (px == py)\n                {\n                    return false;\n                }\n                if (_ranks[px] > _ranks[py])\n                {\n                    _parents[py] = px;\n                    _ranks[px]++;\n                }\n                else\n                {\n                    _parents[px] = py;\n                    _ranks[py]++;\n                }\n                return true;\n            }\n        }\n\n        private int Kruskal(int n, (int from, int to, int w, int origIndex)[] newEdges, int? ignoreIdx, int? forceAddedIdx)\n        {\n            int sum = 0;\n            Unions dsu = new Unions(n);\n            int count = 0;\n\n            if (forceAddedIdx.HasValue)\n            {\n                var edge = newEdges[forceAddedIdx.Value];\n                var v1 = edge.from;\n                var v2 = edge.to;\n                dsu.Union(v1, v2);\n                sum += edge.w;\n                count++;\n            }\n\n            for (int i = 0; i < newEdges.Length; i++)\n            {\n                var edge = newEdges[i];\n                var v1 = edge.from;\n                var v2 = edge.to;\n                if (dsu.Find(v1) == dsu.Find(v2))\n                {\n                    continue;\n                }\n\n                if (ignoreIdx.HasValue && ignoreIdx == i)\n                {\n                    continue;\n                }\n\n                dsu.Union(v1, v2);\n                sum += edge.w;\n                count++;\n            }\n\n            return count == n - 1 ? sum : -1;\n        }\n\n        public IList<IList<int>> FindCriticalAndPseudoCriticalEdges(int n, int[][] edges)\n        {\n            IList<int> crit = new List<int>();\n            IList<int> pseudoCrit = new List<int>();\n\n            (int from, int to, int w, int origIndex)[] newEdges = new (int @from, int to, int w, int origIndex)[edges.Length];\n            for (int i = 0; i < edges.Length; i++)\n            {\n                var edge = edges[i];\n                var v1 = edge[0];\n                var v2 = edge[1];\n                var w = edge[2];\n\n                newEdges[i] = (v1, v2, w, i);\n            }\n\n            Array.Sort(newEdges, (e1, e2) => e1.w.CompareTo(e2.w));\n            int targetSum = Kruskal(n, newEdges, null, null);\n\n\n            for (int i = 0; i < newEdges.Length; i++)\n            {\n                var excludeThis = Kruskal(n, newEdges, i, null);\n                if (excludeThis < 0 || excludeThis > targetSum)\n                {\n                    crit.Add(newEdges[i].origIndex);\n                    continue;\n                }\n\n                var forceIncludeThis = Kruskal(n, newEdges, null, i);\n                if (forceIncludeThis == targetSum)\n                {\n                    pseudoCrit.Add(newEdges[i].origIndex);\n                }\n            }\n\n            \n            return new List<IList<int>>(){crit, pseudoCrit};\n        }\n    }\n```
['Union Find']