Skip to content

Commit 65282b1

Browse files
authored
Create minimum-edge-weight-equilibrium-queries-in-a-tree.cpp
1 parent 2c3988d commit 65282b1

File tree

1 file changed

+247
-0
lines changed

1 file changed

+247
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
// Time: O(r * n + q), r = max(w for _, _, w in edges)
2+
// Space: O(r * n + q)
3+
4+
// Tarjan's Offline LCA Algorithm
5+
class Solution {
6+
private:
7+
static const int MAX_W = 26;
8+
9+
public:
10+
vector<int> minOperationsQueries(int n, vector<vector<int>>& edges, vector<vector<int>>& queries) {
11+
vector<vector<pair<int, int>>> adj(n);
12+
for (const auto& e : edges) {
13+
adj[e[0]].emplace_back(e[1], e[2] - 1), adj[e[1]].emplace_back(e[0], e[2] - 1);
14+
}
15+
unordered_map<int, unordered_set<int>> pairs;
16+
for (const auto& q : queries) {
17+
pairs[q[0]].emplace(q[1]), pairs[q[1]].emplace(q[0]);
18+
}
19+
TreeInfos tree_infos(adj, pairs);
20+
vector<int> result(size(queries));
21+
for (int i = 0; i < size(queries); ++i) {
22+
const auto& a = queries[i][0], &b = queries[i][1];
23+
const auto& lca = tree_infos.lca(a, b);
24+
int mx = 0;
25+
for (int w = 0; w < MAX_W; ++w) {
26+
mx = max(mx, tree_infos.count(a, w) + tree_infos.count(b, w) - 2 * tree_infos.count(lca, w));
27+
}
28+
result[i] = (tree_infos.depth(a) + tree_infos.depth(b) - 2 * tree_infos.depth(lca)) - mx;
29+
}
30+
return result;
31+
}
32+
33+
private:
34+
class UnionFind {
35+
public:
36+
UnionFind(int n)
37+
: set_(n)
38+
, rank_(n)
39+
, ancestor_(n) {
40+
iota(set_.begin(), set_.end(), 0);
41+
iota(ancestor_.begin(), ancestor_.end(), 0); // added
42+
}
43+
44+
int find_set(int x) {
45+
if (set_[x] != x) {
46+
set_[x] = find_set(set_[x]); // Path compression.
47+
}
48+
return set_[x];
49+
}
50+
51+
bool union_set(int x, int y) {
52+
x = find_set(x), y = find_set(y);
53+
if (x == y) {
54+
return false;
55+
}
56+
if (rank_[x] > rank_[y]) {
57+
swap(x, y);
58+
}
59+
set_[x] = y; // Union by rank.
60+
if (rank_[x] == rank_[y]) {
61+
++rank_[y];
62+
}
63+
return true;
64+
}
65+
66+
int find_ancestor_of_set(int x) { // added
67+
return ancestor_[find_set(x)];
68+
}
69+
70+
void update_ancestor_of_set(int x) { // added
71+
ancestor_[find_set(x)] = x;
72+
}
73+
74+
private:
75+
vector<int> set_;
76+
vector<int> rank_;
77+
vector<int> ancestor_; // added
78+
};
79+
80+
class TreeInfos {
81+
public:
82+
TreeInfos(const vector<vector<pair<int, int>>>& adj, const unordered_map<int, unordered_set<int>>& pairs)
83+
: D_(size(adj))
84+
, uf_(size(adj))
85+
, lookup_(size(adj))
86+
, CNT_(size(adj)) // added
87+
, cnt_(MAX_W) { // added
88+
89+
dfs(adj, pairs, 0, -1);
90+
}
91+
92+
int lca(int a, int b) const {
93+
if (a > b) {
94+
swap(a, b);
95+
}
96+
return lca_.at(a).at(b);
97+
}
98+
99+
int depth(int a) const {
100+
return D_[a];
101+
}
102+
103+
int count(int a, int w) const { // added
104+
return CNT_[a][w];
105+
}
106+
107+
private:
108+
void dfs(const vector<vector<pair<int, int>>>& adj,
109+
const unordered_map<int, unordered_set<int>>& pairs,
110+
int u, int p) {
111+
112+
D_[u] = (p == -1) ? 1 : D_[p] + 1;
113+
CNT_[u] = cnt_; // added
114+
for (const auto& [v, w] : adj[u]) {
115+
if (v == p) {
116+
continue;
117+
}
118+
++cnt_[w]; // added
119+
dfs(adj, pairs, v, u);
120+
--cnt_[w]; // added
121+
uf_.union_set(v, u);
122+
uf_.update_ancestor_of_set(u);
123+
}
124+
lookup_[u] = true;
125+
if (!pairs.count(u)) {
126+
return;
127+
}
128+
for (const auto& v : pairs.at(u)) {
129+
if (!lookup_[v]) {
130+
continue;
131+
}
132+
lca_[min(u, v)][max(u, v)] = uf_.find_ancestor_of_set(v);
133+
}
134+
}
135+
136+
vector<int> D_;
137+
UnionFind uf_;
138+
unordered_map<int, unordered_map<int, int>> lca_;
139+
vector<bool> lookup_;
140+
vector<vector<int>> CNT_; // added
141+
vector<int> cnt_; // added
142+
};
143+
};
144+
145+
// Time: O(r * n + nlogn + qlogn), r = max(w for _, _, w in edges)
146+
// Space: O(r * n + nlogn)
147+
// binary lifting (online lca algorithm)
148+
class Solution2 {
149+
private:
150+
static const int MAX_W = 26;
151+
152+
public:
153+
vector<int> minOperationsQueries(int n, vector<vector<int>>& edges, vector<vector<int>>& queries) {
154+
vector<vector<pair<int, int>>> adj(n);
155+
for (const auto& e : edges) {
156+
adj[e[0]].emplace_back(e[1], e[2] - 1), adj[e[1]].emplace_back(e[0], e[2] - 1);
157+
}
158+
TreeInfos tree_infos(adj);
159+
vector<int> result(size(queries));
160+
for (int i = 0; i < size(queries); ++i) {
161+
const auto& a = queries[i][0], &b = queries[i][1];
162+
const auto& lca = tree_infos.lca(a, b);
163+
int mx = 0;
164+
for (int w = 0; w < MAX_W; ++w) {
165+
mx = max(mx, tree_infos.count(a, w) + tree_infos.count(b, w) - 2 * tree_infos.count(lca, w));
166+
}
167+
result[i] = (tree_infos.depth(a) + tree_infos.depth(b) - 2 * tree_infos.depth(lca)) - mx;
168+
}
169+
return result;
170+
}
171+
172+
private:
173+
class TreeInfos {
174+
public:
175+
TreeInfos(const vector<vector<pair<int, int>>>& adj)
176+
: L_(size(adj))
177+
, R_(size(adj))
178+
, D_(size(adj))
179+
, P_(size(adj))
180+
, C_(-1)
181+
, CNT_(size(adj)) // added
182+
, cnt_(MAX_W) { // added
183+
184+
dfs(adj, 0, -1);
185+
}
186+
187+
bool is_ancestor(int a, int b) const {
188+
return L_[a] <= L_[b] && R_[b] <= R_[a];
189+
}
190+
191+
int lca(int a, int b) const {
192+
if (D_[a] > D_[b]) {
193+
swap(a, b);
194+
}
195+
if (is_ancestor(a, b)) {
196+
return a;
197+
}
198+
for (int i = size(P_[a]) - 1; i >= 0; --i) { // O(logN)
199+
if (i < size(P_[a]) && !is_ancestor(P_[a][i], b)) {
200+
a = P_[a][i];
201+
}
202+
}
203+
return P_[a][0];
204+
}
205+
206+
int depth(int a) const {
207+
return D_[a];
208+
}
209+
210+
int count(int a, int w) const { // added
211+
return CNT_[a][w];
212+
}
213+
214+
private:
215+
void dfs(const vector<vector<pair<int, int>>>& adj, int u, int p) {
216+
D_[u] = (p == -1) ? 1 : D_[p] + 1;
217+
if (p != -1) {
218+
P_[u].emplace_back(p); // ancestors of the node i
219+
}
220+
for (int i = 0; i < size(P_[u]); ++i) {
221+
if (i >= size(P_[P_[u][i]])) {
222+
break;
223+
}
224+
P_[u].emplace_back(P_[P_[u][i]][i]);
225+
}
226+
L_[u] = ++C_;
227+
CNT_[u] = cnt_; // added
228+
for (const auto& [v, w] : adj[u]) {
229+
if (v == p) {
230+
continue;
231+
}
232+
++cnt_[w]; // added
233+
dfs(adj, v, u);
234+
--cnt_[w]; // added
235+
}
236+
R_[u] = C_;
237+
}
238+
239+
vector<int> L_;
240+
vector<int> R_;
241+
vector<int> D_;
242+
vector<vector<int>> P_;
243+
int C_;
244+
vector<vector<int>> CNT_; // added
245+
vector<int> cnt_; // added
246+
};
247+
};

0 commit comments

Comments
 (0)