Skip to content

Commit b47be55

Browse files
authored
Create minimum-weighted-subgraph-with-the-required-paths-ii.cpp
1 parent 06479d0 commit b47be55

File tree

1 file changed

+148
-0
lines changed

1 file changed

+148
-0
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// Time: O(n + q)
2+
// Space: O(n + q)
3+
4+
class UnionFind {
5+
public:
6+
UnionFind(int n)
7+
: set_(n)
8+
, rank_(n) {
9+
iota(begin(set_), end(set_), 0);
10+
}
11+
12+
int find_set(int x) {
13+
vector<int> stk;
14+
while (set_[x] != x) { // path compression
15+
stk.emplace_back(x);
16+
x = set_[x];
17+
}
18+
return x;
19+
}
20+
21+
bool union_set(int x, int y) {
22+
x = find_set(x), y = find_set(y);
23+
if (x == y) {
24+
return false;
25+
}
26+
if (rank_[x] > rank_[y]) {
27+
swap(x, y);
28+
}
29+
set_[x] = y; // Union by rank.
30+
if (rank_[x] == rank_[y]) {
31+
++rank_[y];
32+
}
33+
return true;
34+
}
35+
36+
private:
37+
vector<int> set_;
38+
vector<int> rank_;
39+
};
40+
41+
// iterative dfs, Tarjan's Offline LCA Algorithm
42+
class Solution {
43+
public:
44+
vector<int> minimumWeight(vector<vector<int>>& edges, vector<vector<int>>& queries) {
45+
vector<vector<pair<int, int>>> adj(size(edges) + 1);
46+
for (const auto& e : edges) {
47+
adj[e[0]].emplace_back(e[1], e[2]);
48+
adj[e[1]].emplace_back(e[0], e[2]);
49+
}
50+
const auto& iter_dfs = [&]() {
51+
vector<bool> lookup(size(adj));
52+
vector<vector<int>> lookup2(size(adj));
53+
for (int i = 0; i < size(queries); ++i) {
54+
for (const auto& x : queries[i]) {
55+
lookup2[x].emplace_back(i);
56+
}
57+
}
58+
UnionFind uf(size(adj));
59+
vector<int> ancestor(size(adj));
60+
iota(begin(ancestor), end(ancestor), 0);
61+
vector<int> dist(size(adj));
62+
vector<int> result(size(queries));
63+
vector<tuple<int, int, int, int>> stk = {{1, 0, -1, -1}};
64+
while (!empty(stk)) {
65+
const auto [step, u, p, i] = stk.back(); stk.pop_back();
66+
if (step == 1) {
67+
for (const auto& i : lookup2[u]) {
68+
result[i] += dist[u];
69+
for (const auto& x : queries[i]) {
70+
if (lookup[x]) {
71+
result[i] -= dist[ancestor[uf.find_set(x)]];
72+
}
73+
}
74+
}
75+
lookup[u] = true;
76+
stk.emplace_back(2, u, -1, 0);
77+
} else if (step == 2) {
78+
if (i == size(adj[u])) {
79+
continue;
80+
}
81+
const auto& [v, w] = adj[u][i];
82+
stk.emplace_back(2, u, -1, i + 1);
83+
if (lookup[v]) {
84+
continue;
85+
}
86+
dist[v] = dist[u] + w;
87+
stk.emplace_back(3, v, u, -1);
88+
stk.emplace_back(1, v, -1, -1);
89+
} else if (step == 3) {
90+
uf.union_set(u, p);
91+
ancestor[uf.find_set(p)] = p;
92+
}
93+
}
94+
return result;
95+
};
96+
97+
return iter_dfs();
98+
}
99+
};
100+
101+
// Time: O(n + q)
102+
// Space: O(n + q)
103+
// dfs, Tarjan's Offline LCA Algorithm
104+
class Solution2 {
105+
public:
106+
vector<int> minimumWeight(vector<vector<int>>& edges, vector<vector<int>>& queries) {
107+
vector<vector<pair<int, int>>> adj(size(edges) + 1);
108+
for (const auto& e : edges) {
109+
adj[e[0]].emplace_back(e[1], e[2]);
110+
adj[e[1]].emplace_back(e[0], e[2]);
111+
}
112+
vector<bool> lookup(size(adj));
113+
vector<vector<int>> lookup2(size(adj));
114+
for (int i = 0; i < size(queries); ++i) {
115+
for (const auto& x : queries[i]) {
116+
lookup2[x].emplace_back(i);
117+
}
118+
}
119+
UnionFind uf(size(adj));
120+
vector<int> ancestor(size(adj));
121+
iota(begin(ancestor), end(ancestor), 0);
122+
vector<int> dist(size(adj));
123+
vector<int> result(size(queries));
124+
const function<void (int)> dfs = [&](int u) {
125+
for (const auto& i : lookup2[u]) {
126+
result[i] += dist[u];
127+
for (const auto& x : queries[i]) {
128+
if (lookup[x]) {
129+
result[i] -= dist[ancestor[uf.find_set(x)]];
130+
}
131+
}
132+
}
133+
lookup[u] = true;
134+
for (const auto& [v, w] : adj[u]) {
135+
if (lookup[v]) {
136+
continue;
137+
}
138+
dist[v] = dist[u] + w;
139+
dfs(v);
140+
uf.union_set(v, u);
141+
ancestor[uf.find_set(u)] = u;
142+
}
143+
};
144+
145+
dfs(0);
146+
return result;
147+
}
148+
};

0 commit comments

Comments
 (0)