Priority Queue Java Solution
IntuitionWe first build a reverse graph of the original edges, so that we can try to reach all nodes from 0. We use a priority queue to store all the reversed e
# Intuition
We first build a reverse graph of the original edges, so that we can try to reach all nodes from 0. We use a priority queue to store all the reversed edges, so that we always using the edge with the minimum weight.

# Approach
From the edges, we build a reverse graph, where edge `a->b` is saved as an reverse edge `b->a` with same weights. We ignore the original `0->` outward paths, as we only want to make sure 0 is accessible for all nodes by the original edges.
We use a set to store the reachable nodes from 0 by the reversed edge.
We use a priority queue to store the reversed edges, starting from the reversed edges from 0, with weight as the key (from small to large).
While the number of reachable nodes are less than n and that the priority queue is not empty, we pop the reversed edge with smallest weight, we add the node to the reachable set, and update the min max weight with the edge's weight, as it is used by us to connect the node to 0. Then, for each neighbor node of the end node of the reversed edge, if it is not already in the reachable set, we add the reversed edge into the priority queue.
We return if the reachable size is n in the end.

# Complexity
- Time complexity:
$$O(E \log E)$$

- Space complexity:
$$O(E)$$

# Code
```java []
class Solution {
    public int minMaxWeight(int n, int[][] edges, int threshold) {
        // reverseGraph[node] is the reversed path for node 
        List<Map<Integer,Integer>> reverseGraph = new ArrayList<>();

        for (int i = 0; i < n; i++) {
            reverseGraph.add(new HashMap<>()); // initialize the list
        }

        for (int[] edge: edges) {
            if (edge[0] == 0) continue; // No need to add edge starting from 0
            Map<Integer, Integer> edgeMap = reverseGraph.get(edge[1]);
            // start: edge[1], end: edge[0], weight: edge[2] 
            // For the current start, we either:
            // 1. add an edge to end with weight, if there isn't path start -> end
            // 2. if there is such a path, we update its weight to be the smaller one
            edgeMap.put(edge[0], 
                Math.min(
                    edgeMap.getOrDefault(edge[0], Integer.MAX_VALUE), 
                    edge[2])
            );
        }

        // reachableSet is the nodes that can reach 0
        Set<Integer> reachableSet = new HashSet<>();
        reachableSet.add(0);

        int ans = 0; // the min max weight

        // use a pq to store all edges, with weight as the key
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
        
        // add all paths from 0 to pq
        // the int[] is {weight, from, to}
        for (Map.Entry<Integer, Integer> edge: reverseGraph.get(0).entrySet()) {
            pq.offer(new int[] {edge.getValue(), 0, edge.getKey()});
        }        

        while (reachableSet.size() < n && !pq.isEmpty()) {
            int[] edge = pq.poll();
            int weight = edge[0], start = edge[1], end = edge[2];

            if (reachableSet.contains(end)) continue; 
            // since we add nodes with path weights small to large,
            // if the node is already reachable, no need to process again,
            // as the weight must be larger

            // add the current end to the reachable
            reachableSet.add(end);

            // udpate the min max weight
            ans = Math.max(ans, weight);
            
            Map<Integer, Integer> edgeMap = reverseGraph.get(end);
            // for each outgoing paths of the end, add to the pq
            for (Map.Entry<Integer, Integer> e: edgeMap.entrySet()) {
                pq.offer(new int[] {e.getValue(), end, e.getKey()});
            }
        }

        return reachableSet.size() == n ? ans : -1;
    }
}
```
['Heap (Priority Queue)', 'Java']