<JAVA> 19
Code\n\nclass Solution {\n    public List<List<Integer>> findCriticalAndPseudoCriticalEdges(int n, int[][] edges) {\n        // Add index to edges for tracking\
# Code\n```\nclass Solution {\n    public List<List<Integer>> findCriticalAndPseudoCriticalEdges(int n, int[][] edges) {\n        // Add index to edges for tracking\n        int m = edges.length;\n        int[][] newEdges = new int[m][4];\n\n        for (int i = 0; i < m; i++) {\n            for (int j = 0; j < 3; j++) {\n                newEdges[i][j] = edges[i][j];\n            }\n            newEdges[i][3] = i;\n        }\n\n        // Sort edges based on weight\n        Arrays.sort(newEdges, Comparator.comparingInt(edge -> edge[2]));\n\n        // Find MST weight using union-find\n        UnionFind ufStd = new UnionFind(n);\n        int stdWeight = 0;\n        for (int[] edge : newEdges) {\n            if (ufStd.union(edge[0], edge[1])) {\n                stdWeight += edge[2];\n            }\n        }\n\n        List<List<Integer>> result = new ArrayList<>();\n        for (int i = 0; i < 2; i++) {\n            result.add(new ArrayList<>());\n        }\n\n        // Check each edge for critical and pseudo-critical\n        for (int i = 0; i < m; i++) {\n            // Ignore this edge and calculate MST weight\n            UnionFind ufIgnore = new UnionFind(n);\n            int ignoreWeight = 0;\n            for (int j = 0; j < m; j++) {\n                if (i != j && ufIgnore.union(newEdges[j][0], newEdges[j][1])) {\n                    ignoreWeight += newEdges[j][2];\n                }\n            }\n            // If the graph is disconnected or the total weight is greater, \n            // the edge is critical\n            if (ufIgnore.maxSize < n || ignoreWeight > stdWeight) {\n                result.get(0).add(newEdges[i][3]);\n            } else {\n                // Force this edge and calculate MST weight\n                UnionFind ufForce = new UnionFind(n);\n                ufForce.union(newEdges[i][0], newEdges[i][1]);\n                int forceWeight = newEdges[i][2];\n                for (int j = 0; j < m; j++) {\n                    if (i != j && ufForce.union(newEdges[j][0], newEdges[j][1])) {\n                        forceWeight += newEdges[j][2];\n                    }\n                }\n                // If total weight is the same, the edge is pseudo-critical\n                if (forceWeight == stdWeight) {\n                    result.get(1).add(newEdges[i][3]);\n                }\n            }\n        }\n\n        return result;\n    }\n\n    class UnionFind {\n        int[] parent;\n        int[] size;\n        int maxSize;\n\n        public UnionFind(int n) {\n            parent = new int[n];\n            size = new int[n];\n            maxSize = 1;\n            for (int i = 0; i < n; i++) {\n                parent[i] = i;\n                size[i] = 1;\n            }\n        }\n\n        public int find(int x) {\n            // Finds the root of x\n            if (x != parent[x]) {\n                parent[x] = find(parent[x]);\n            }\n            return parent[x];\n        }\n\n        public boolean union(int x, int y) {\n            // Connects x and y\n            int rootX = find(x);\n            int rootY = find(y);\n            if (rootX != rootY) {\n                if (size[rootX] < size[rootY]) {\n                    int temp = rootX;\n                    rootX = rootY;\n                    rootY = temp;\n                }\n                parent[rootY] = rootX;\n                size[rootX] += size[rootY];\n                maxSize = Math.max(maxSize, size[rootX]);\n                return true;\n            }\n            return false;\n        }\n    }\n}//TC:O(m^2\u22C5\u03B1(n)), where m is the number of edges, n is the number of nodes and \u03B1\\alpha\u03B1 is the inverse Ackermann function; SC:O(m)\n```
['Java']