Skip to content

Commit 3af3305

Browse files
authored
feat: add solutions to lc problem: No.2846 (#1575)
No.2846.Minimum Edge Weight Equilibrium Queries in a Tree
1 parent 83fefc6 commit 3af3305

File tree

6 files changed

+769
-7
lines changed

6 files changed

+769
-7
lines changed

solution/2800-2899/2846.Minimum Edge Weight Equilibrium Queries in a Tree/README.md

+270-4
Original file line numberDiff line numberDiff line change
@@ -65,34 +65,300 @@
6565

6666
<!-- 这里可写通用的实现逻辑 -->
6767

68+
**方法一:倍增法求 LCA**
69+
70+
题目求的是任意两点的路径上,将其所有边的权重变成相同值的最小操作次数。实际上就是求这两点之间的路径长度,减去路径上出现次数最多的边的次数。
71+
72+
而求两点间的路径长度,可以通过倍增法求 LCA 来实现。我们记两点分别为 $u$ 和 $v$,最近公共祖先为 $x$,那么 $u$ 到 $v$ 的路径长度就是 $depth(u) + depth(v) - 2 \times depth(x)$。
73+
74+
另外,我们可以用一个数组 $cnt[n][26]$ 记录根节点到每个节点上,每个边权重出现的次数。那么 $u$ 到 $v$ 的路径上,出现次数最多的边的次数就是 $\max_{0 \leq j < 26} cnt[u][j] + cnt[v][j] - 2 \times cnt[x][j]$。其中 $x$ 为 $u$ 和 $v$ 的最近公共祖先。
75+
76+
倍增法求 LCA 的过程如下:
77+
78+
我们记每个节点的深度为 $depth$,父节点为 $p$,而 $f[i][j]$ 表示节点 $i$ 的第 $2^j$ 个祖先。那么,对于任意两点 $x$ 和 $y$,我们可以通过以下方式求出它们的最近公共祖先:
79+
80+
1. 如果 $depth(x) < depth(y)$,那么交换 $x$ 和 $y$,即保证 $x$ 的深度不小于 $y$ 的深度;
81+
2. 接下来,我们将 $x$ 的深度不断向上提升,直到 $x$ 和 $y$ 的深度相同,此时 $x$ 和 $y$ 的深度都为 $depth(x)$;
82+
3. 然后,我们将 $x$ 和 $y$ 的深度同时向上提升,直到 $x$ 和 $y$ 的父节点相同,此时 $x$ 和 $y$ 的父节点都为 $f[x][0]$,即为 $x$ 和 $y$ 的最近公共祖先。
83+
84+
最后,节点 $u$ 到节点 $v$ 的最小操作次数就是 $depth(u) + depth(v) - 2 \times depth(x) - \max_{0 \leq j < 26} cnt[u][j] + cnt[v][j] - 2 \times cnt[x][j]$。
85+
86+
时间复杂度 $O((n + q) \times C \times \log n)$,空间复杂度 $O(n \times C \times \log n)$,其中 $C$ 为边权重的最大值。
87+
6888
<!-- tabs:start -->
6989

7090
### **Python3**
7191

7292
<!-- 这里可写当前语言的特殊实现逻辑 -->
7393

7494
```python
75-
95+
class Solution:
96+
def minOperationsQueries(
97+
self, n: int, edges: List[List[int]], queries: List[List[int]]
98+
) -> List[int]:
99+
m = n.bit_length()
100+
g = [[] for _ in range(n)]
101+
f = [[0] * m for _ in range(n)]
102+
p = [0] * n
103+
cnt = [None] * n
104+
depth = [0] * n
105+
for u, v, w in edges:
106+
g[u].append((v, w - 1))
107+
g[v].append((u, w - 1))
108+
cnt[0] = [0] * 26
109+
q = deque([0])
110+
while q:
111+
i = q.popleft()
112+
f[i][0] = p[i]
113+
for j in range(1, m):
114+
f[i][j] = f[f[i][j - 1]][j - 1]
115+
for j, w in g[i]:
116+
if j != p[i]:
117+
p[j] = i
118+
cnt[j] = cnt[i][:]
119+
cnt[j][w] += 1
120+
depth[j] = depth[i] + 1
121+
q.append(j)
122+
ans = []
123+
for u, v in queries:
124+
x, y = u, v
125+
if depth[x] < depth[y]:
126+
x, y = y, x
127+
for j in reversed(range(m)):
128+
if depth[x] - depth[y] >= (1 << j):
129+
x = f[x][j]
130+
for j in reversed(range(m)):
131+
if f[x][j] != f[y][j]:
132+
x, y = f[x][j], f[y][j]
133+
if x != y:
134+
x = p[x]
135+
mx = max(cnt[u][j] + cnt[v][j] - 2 * cnt[x][j] for j in range(26))
136+
ans.append(depth[u] + depth[v] - 2 * depth[x] - mx)
137+
return ans
76138
```
77139

78140
### **Java**
79141

80142
<!-- 这里可写当前语言的特殊实现逻辑 -->
81143

82144
```java
83-
145+
class Solution {
146+
public int[] minOperationsQueries(int n, int[][] edges, int[][] queries) {
147+
int m = 32 - Integer.numberOfLeadingZeros(n);
148+
List<int[]>[] g = new List[n];
149+
Arrays.setAll(g, i -> new ArrayList<>());
150+
int[][] f = new int[n][m];
151+
int[] p = new int[n];
152+
int[][] cnt = new int[n][0];
153+
int[] depth = new int[n];
154+
for (var e : edges) {
155+
int u = e[0], v = e[1], w = e[2] - 1;
156+
g[u].add(new int[] {v, w});
157+
g[v].add(new int[] {u, w});
158+
}
159+
cnt[0] = new int[26];
160+
Deque<Integer> q = new ArrayDeque<>();
161+
q.offer(0);
162+
while (!q.isEmpty()) {
163+
int i = q.poll();
164+
f[i][0] = p[i];
165+
for (int j = 1; j < m; ++j) {
166+
f[i][j] = f[f[i][j - 1]][j - 1];
167+
}
168+
for (var nxt : g[i]) {
169+
int j = nxt[0], w = nxt[1];
170+
if (j != p[i]) {
171+
p[j] = i;
172+
cnt[j] = cnt[i].clone();
173+
cnt[j][w]++;
174+
depth[j] = depth[i] + 1;
175+
q.offer(j);
176+
}
177+
}
178+
}
179+
int k = queries.length;
180+
int[] ans = new int[k];
181+
for (int i = 0; i < k; ++i) {
182+
int u = queries[i][0], v = queries[i][1];
183+
int x = u, y = v;
184+
if (depth[x] < depth[y]) {
185+
int t = x;
186+
x = y;
187+
y = t;
188+
}
189+
for (int j = m - 1; j >= 0; --j) {
190+
if (depth[x] - depth[y] >= (1 << j)) {
191+
x = f[x][j];
192+
}
193+
}
194+
for (int j = m - 1; j >= 0; --j) {
195+
if (f[x][j] != f[y][j]) {
196+
x = f[x][j];
197+
y = f[y][j];
198+
}
199+
}
200+
if (x != y) {
201+
x = p[x];
202+
}
203+
int mx = 0;
204+
for (int j = 0; j < 26; ++j) {
205+
mx = Math.max(mx, cnt[u][j] + cnt[v][j] - 2 * cnt[x][j]);
206+
}
207+
ans[i] = depth[u] + depth[v] - 2 * depth[x] - mx;
208+
}
209+
return ans;
210+
}
211+
}
84212
```
85213

86214
### **C++**
87215

88216
```cpp
89-
217+
class Solution {
218+
public:
219+
vector<int> minOperationsQueries(int n, vector<vector<int>>& edges, vector<vector<int>>& queries) {
220+
int m = 32 - __builtin_clz(n);
221+
vector<pair<int, int>> g[n];
222+
int f[n][m];
223+
int p[n];
224+
int cnt[n][26];
225+
int depth[n];
226+
memset(f, 0, sizeof(f));
227+
memset(cnt, 0, sizeof(cnt));
228+
memset(depth, 0, sizeof(depth));
229+
memset(p, 0, sizeof(p));
230+
for (auto& e : edges) {
231+
int u = e[0], v = e[1], w = e[2] - 1;
232+
g[u].emplace_back(v, w);
233+
g[v].emplace_back(u, w);
234+
}
235+
queue<int> q;
236+
q.push(0);
237+
while (!q.empty()) {
238+
int i = q.front();
239+
q.pop();
240+
f[i][0] = p[i];
241+
for (int j = 1; j < m; ++j) {
242+
f[i][j] = f[f[i][j - 1]][j - 1];
243+
}
244+
for (auto& [j, w] : g[i]) {
245+
if (j != p[i]) {
246+
p[j] = i;
247+
memcpy(cnt[j], cnt[i], sizeof(cnt[i]));
248+
cnt[j][w]++;
249+
depth[j] = depth[i] + 1;
250+
q.push(j);
251+
}
252+
}
253+
}
254+
vector<int> ans;
255+
for (auto& qq : queries) {
256+
int u = qq[0], v = qq[1];
257+
int x = u, y = v;
258+
if (depth[x] < depth[y]) {
259+
swap(x, y);
260+
}
261+
for (int j = m - 1; ~j; --j) {
262+
if (depth[x] - depth[y] >= (1 << j)) {
263+
x = f[x][j];
264+
}
265+
}
266+
for (int j = m - 1; ~j; --j) {
267+
if (f[x][j] != f[y][j]) {
268+
x = f[x][j];
269+
y = f[y][j];
270+
}
271+
}
272+
if (x != y) {
273+
x = p[x];
274+
}
275+
int mx = 0;
276+
for (int j = 0; j < 26; ++j) {
277+
mx = max(mx, cnt[u][j] + cnt[v][j] - 2 * cnt[x][j]);
278+
}
279+
ans.push_back(depth[u] + depth[v] - 2 * depth[x] - mx);
280+
}
281+
return ans;
282+
}
283+
};
90284
```
91285
92286
### **Go**
93287
94288
```go
95-
289+
func minOperationsQueries(n int, edges [][]int, queries [][]int) []int {
290+
m := bits.Len(uint(n))
291+
g := make([][][2]int, n)
292+
f := make([][]int, n)
293+
for i := range f {
294+
f[i] = make([]int, m)
295+
}
296+
p := make([]int, n)
297+
cnt := make([][26]int, n)
298+
cnt[0] = [26]int{}
299+
depth := make([]int, n)
300+
for _, e := range edges {
301+
u, v, w := e[0], e[1], e[2]-1
302+
g[u] = append(g[u], [2]int{v, w})
303+
g[v] = append(g[v], [2]int{u, w})
304+
}
305+
q := []int{0}
306+
for len(q) > 0 {
307+
i := q[0]
308+
q = q[1:]
309+
f[i][0] = p[i]
310+
for j := 1; j < m; j++ {
311+
f[i][j] = f[f[i][j-1]][j-1]
312+
}
313+
for _, nxt := range g[i] {
314+
j, w := nxt[0], nxt[1]
315+
if j != p[i] {
316+
p[j] = i
317+
cnt[j] = [26]int{}
318+
for k := 0; k < 26; k++ {
319+
cnt[j][k] = cnt[i][k]
320+
}
321+
cnt[j][w]++
322+
depth[j] = depth[i] + 1
323+
q = append(q, j)
324+
}
325+
}
326+
}
327+
ans := make([]int, len(queries))
328+
for i, qq := range queries {
329+
u, v := qq[0], qq[1]
330+
x, y := u, v
331+
if depth[x] < depth[y] {
332+
x, y = y, x
333+
}
334+
for j := m - 1; j >= 0; j-- {
335+
if depth[x]-depth[y] >= (1 << j) {
336+
x = f[x][j]
337+
}
338+
}
339+
for j := m - 1; j >= 0; j-- {
340+
if f[x][j] != f[y][j] {
341+
x, y = f[x][j], f[y][j]
342+
}
343+
}
344+
if x != y {
345+
x = p[x]
346+
}
347+
mx := 0
348+
for j := 0; j < 26; j++ {
349+
mx = max(mx, cnt[u][j]+cnt[v][j]-2*cnt[x][j])
350+
}
351+
ans[i] = depth[u] + depth[v] - 2*depth[x] - mx
352+
}
353+
return ans
354+
}
355+
356+
func max(a, b int) int {
357+
if a > b {
358+
return a
359+
}
360+
return b
361+
}
96362
```
97363

98364
### **...**

0 commit comments

Comments
 (0)