Cover image for LeetCode Daily Problem P3607 Power Grid Maintenance

LeetCode Daily Problem P3607 Power Grid Maintenance


Timeline

Timeline

2025-11-07

init


Problem:

DFS + min-heap + lazy deletion

The following code will get WA because it maintains a min-heap of all nodes reachable from each node. If a node is taken offline, it only lazily deletes that node from the heaps of all nodes that can reach it, without considering nodes that can only be reached through that node; such nodes also become unreachable. Moreover, the structure of the power grid is fixed; offline (non-operational) nodes still belong to their power grid, and offline operations do not change the connectivity of the grid.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
#include <vector>#include <unordered_set>#include <queue>#include <unordered_map>#include <stack>#include <algorithm>using std::vector;using std::unordered_set;using std::priority_queue;using std::unordered_map;using std::stack;typedef priority_queue<int, vector<int>, std::greater<int> > MinHeap;class Solution {    public:	vector<int> processQueries(int c, vector<vector<int> > &connections, vector<vector<int> > &queries)	{		vector<bool> work_states = vector<bool>(c, true);		vector<MinHeap> neighbors_heap = vector<MinHeap>(c, MinHeap());		vector<unordered_set<int> > to_be_deleted = vector<unordered_set<int> >(c);		unordered_map<int, vector<int> > graph;		vector<int> res;		int i = 0, j = 0, n, connection_size = connections.size();		int p_stat1, p_stat2;		// Build the graph		for (i = 0; i < c; i++) { // Numbered from 0 to c-1			graph[i] = vector<int>();		}		for (i = 0; i < connection_size; i++) {			p_stat1 = connections[i][0] - 1; // Numbered starting from 0			p_stat2 = connections[i][1] - 1;			graph[p_stat1].push_back(p_stat2);			graph[p_stat2].push_back(p_stat1);		}		// Populate neighbors_heap		int top;		vector<bool> visited = vector<bool>(c, false);		vector<vector<int> > graph_components;		for (i = 0; i < c; i++) { // Depth-first traversal			if (visited[i]) {				continue;			}			stack<int> st;			st.push(i);			vector<int> curr_graph;			while (!st.empty()) {				top = st.top();				st.pop();				if (!visited[top]) {					visited[top] = true;					curr_graph.push_back(top);				}				for (int node : graph[top]) {					if (!visited[node]) {						st.push(node);					}				}			}			graph_components.push_back(curr_graph);		}		for (vector<int> v : graph_components) { //Each connected component of the graph			n = v.size();			for (i = 0; i < n; i++) {				for (j = 0; j < n; j++) {					if (j == i) {						continue;					}					neighbors_heap[v[i]].push(v[j]);				}			}		}		int query_size = queries.size();		int ops, p_stat;		bool flag;		for (i = 0; i < query_size; i++) {			ops = queries[i][0];			p_stat = queries[i][1] - 1;			if (ops == 1) { // maintence				if (work_states[p_stat]) { // p_stat is online, handle it directly					res.push_back(p_stat + 1);				} else { //the smallest in its neighbor_heap					flag = true;					while (!neighbors_heap[p_stat].empty()) {						top = neighbors_heap[p_stat].top();						if (!to_be_deleted[p_stat].count(top)) { // No need to delete							res.push_back(top + 1);							flag = false;							break;						} else {							neighbors_heap[p_stat].pop();							to_be_deleted[p_stat].erase(top);						}					}					if (flag) {						res.push_back(-1);					}				}			} else if (ops == 2) { // goes offline				work_states[p_stat] = false; // Mark p_stat as offline				for (int ps : graph[p_stat]) { // All references to p_stat are marked for deletion					to_be_deleted[ps].insert(p_stat);				}			}		}		return res;	}};

Official solution:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
class Vertex {public:    int vertexId;    bool offline = false;    int powerGridId = -1;    Vertex() {}    Vertex(int id) : vertexId(id) {}};using PowerGrid = priority_queue<int, vector<int>, greater<int>>;using Graph = vector<vector<int>>;class Solution {private:    vector<Vertex> vertices = vector<Vertex>();    void traverse(Vertex& u, int powerGridId, PowerGrid& powerGrid,                  Graph& graph) {        u.powerGridId = powerGridId;        powerGrid.push(u.vertexId);        for (int vid : graph[u.vertexId]) {            Vertex& v = vertices[vid];            if (v.powerGridId == -1)                traverse(v, powerGridId, powerGrid, graph);        }    }public:    vector<int> processQueries(int c, vector<vector<int>>& connections,                               vector<vector<int>>& queries) {        Graph graph(c + 1);        vertices.resize(c + 1);        for (int i = 1; i <= c; i++) {            vertices[i] = Vertex(i);        }        for (auto& conn : connections) {            graph[conn.at(0)].push_back(conn.at(1));            graph[conn.at(1)].push_back(conn.at(0));        }        vector<PowerGrid> powerGrids;        for (int i = 1, powerGridId = 0; i <= c; i++) {            auto& v = vertices[i];            if (v.powerGridId == -1) {                PowerGrid powerGrid;                traverse(v, powerGridId, powerGrid, graph);                powerGrids.push_back(powerGrid);                powerGridId++;            }        }        vector<int> ans;        for (auto& q : queries) {            int op = q.at(0), x = q.at(1);            if (op == 1) {                if (!vertices[x].offline) {                    ans.push_back(x);                } else {                    auto& powerGrid = powerGrids[vertices[x].powerGridId];                    while (!powerGrid.empty() &&                           vertices[powerGrid.top()].offline) {                        powerGrid.pop();                    }                    ans.push_back(!powerGrid.empty() ? powerGrid.top() : -1);                }            } else if (op == 2) {                vertices[x].offline = true;            }        }        return ans;    }};

Disjoint Set Union (DSU)

This method is a bit hard to think of:

Difficulty: operations are performed online, and offline operations affect subsequent queries.
But the problem says the grid structure is fixed, i.e., going offline does not change connectivity. Therefore, we can think in reverse: if we view the operations from back to front, ‘offline’ becomes ‘back online’!
So the algorithm uses a reverse process:

  • First, preprocess the final state of all nodes (which ones are offline at the end).
  • Then process from the last operation backwards.
  • Treat ‘offline’ as ‘back online’.
  • Use a Disjoint Set Union (DSU) to maintain the minimum online number in each power grid.
    Official solution:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
class DSU {public:    vector<int> parent;    DSU(int size) {        parent.resize(size);        iota(parent.begin(), parent.end(), 0);    }    int find(int x) { return parent[x] == x ? x : parent[x] = find(parent[x]); }    void join(int u, int v) { parent[find(v)] = find(u); }};class Solution {public:    vector<int> processQueries(int c, vector<vector<int>>& connections,                               vector<vector<int>>& queries) {        DSU dsu(c + 1);        for (auto& p : connections) {            dsu.join(p[0], p[1]);        }        vector<bool> online(c + 1, true);        vector<int> offlineCounts(c + 1, 0);        unordered_map<int, int> minimumOnlineStations;        for (auto& q : queries) {            int op = q[0], x = q[1];            if (op == 2) {                online[x] = false;                offlineCounts[x]++;            }        }        for (int i = 1; i <= c; i++) {            int root = dsu.find(i);            if (!minimumOnlineStations.count(root)) {                minimumOnlineStations[root] = -1;            }            int station = minimumOnlineStations[root];            if (online[i]) {                if (station == -1 || station > i) {                    minimumOnlineStations[root] = i;                }            }        }        vector<int> ans;        for (int i = (int)queries.size() - 1; i >= 0; i--) {            int op = queries[i][0], x = queries[i][1];            int root = dsu.find(x);            int station = minimumOnlineStations[root];            if (op == 1) {                if (online[x]) {                    ans.push_back(x);                } else {                    ans.push_back(station);                }            }            if (op == 2) {                if (offlineCounts[x] > 1) {                    offlineCounts[x]--;                } else {                    online[x] = true;                    if (station == -1 || station > x) {                        minimumOnlineStations[root] = x;                    }                }            }        }        reverse(ans.begin(), ans.end());        return ans;    }};
Loading comments…