Skip to content

feat: add solutions to lc problem: No.2846 #1575

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,34 +65,300 @@

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

**方法一:倍增法求 LCA**

题目求的是任意两点的路径上,将其所有边的权重变成相同值的最小操作次数。实际上就是求这两点之间的路径长度,减去路径上出现次数最多的边的次数。

而求两点间的路径长度,可以通过倍增法求 LCA 来实现。我们记两点分别为 $u$ 和 $v$,最近公共祖先为 $x$,那么 $u$ 到 $v$ 的路径长度就是 $depth(u) + depth(v) - 2 \times depth(x)$。

另外,我们可以用一个数组 $cnt[n][26]$ 记录根节点到每个节点上,每个边权重出现的次数。那么 $u$ 到 $v$ 的路径上,出现次数最多的边的次数就是 $\max_{0 \leq j < 26} cnt[u][j] + cnt[v][j] - 2 \times cnt[x][j]$。其中 $x$ 为 $u$ 和 $v$ 的最近公共祖先。

倍增法求 LCA 的过程如下:

我们记每个节点的深度为 $depth$,父节点为 $p$,而 $f[i][j]$ 表示节点 $i$ 的第 $2^j$ 个祖先。那么,对于任意两点 $x$ 和 $y$,我们可以通过以下方式求出它们的最近公共祖先:

1. 如果 $depth(x) < depth(y)$,那么交换 $x$ 和 $y$,即保证 $x$ 的深度不小于 $y$ 的深度;
2. 接下来,我们将 $x$ 的深度不断向上提升,直到 $x$ 和 $y$ 的深度相同,此时 $x$ 和 $y$ 的深度都为 $depth(x)$;
3. 然后,我们将 $x$ 和 $y$ 的深度同时向上提升,直到 $x$ 和 $y$ 的父节点相同,此时 $x$ 和 $y$ 的父节点都为 $f[x][0]$,即为 $x$ 和 $y$ 的最近公共祖先。

最后,节点 $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]$。

时间复杂度 $O((n + q) \times C \times \log n)$,空间复杂度 $O(n \times C \times \log n)$,其中 $C$ 为边权重的最大值。

<!-- tabs:start -->

### **Python3**

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

```python

class Solution:
def minOperationsQueries(
self, n: int, edges: List[List[int]], queries: List[List[int]]
) -> List[int]:
m = n.bit_length()
g = [[] for _ in range(n)]
f = [[0] * m for _ in range(n)]
p = [0] * n
cnt = [None] * n
depth = [0] * n
for u, v, w in edges:
g[u].append((v, w - 1))
g[v].append((u, w - 1))
cnt[0] = [0] * 26
q = deque([0])
while q:
i = q.popleft()
f[i][0] = p[i]
for j in range(1, m):
f[i][j] = f[f[i][j - 1]][j - 1]
for j, w in g[i]:
if j != p[i]:
p[j] = i
cnt[j] = cnt[i][:]
cnt[j][w] += 1
depth[j] = depth[i] + 1
q.append(j)
ans = []
for u, v in queries:
x, y = u, v
if depth[x] < depth[y]:
x, y = y, x
for j in reversed(range(m)):
if depth[x] - depth[y] >= (1 << j):
x = f[x][j]
for j in reversed(range(m)):
if f[x][j] != f[y][j]:
x, y = f[x][j], f[y][j]
if x != y:
x = p[x]
mx = max(cnt[u][j] + cnt[v][j] - 2 * cnt[x][j] for j in range(26))
ans.append(depth[u] + depth[v] - 2 * depth[x] - mx)
return ans
```

### **Java**

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

```java

class Solution {
public int[] minOperationsQueries(int n, int[][] edges, int[][] queries) {
int m = 32 - Integer.numberOfLeadingZeros(n);
List<int[]>[] g = new List[n];
Arrays.setAll(g, i -> new ArrayList<>());
int[][] f = new int[n][m];
int[] p = new int[n];
int[][] cnt = new int[n][0];
int[] depth = new int[n];
for (var e : edges) {
int u = e[0], v = e[1], w = e[2] - 1;
g[u].add(new int[] {v, w});
g[v].add(new int[] {u, w});
}
cnt[0] = new int[26];
Deque<Integer> q = new ArrayDeque<>();
q.offer(0);
while (!q.isEmpty()) {
int i = q.poll();
f[i][0] = p[i];
for (int j = 1; j < m; ++j) {
f[i][j] = f[f[i][j - 1]][j - 1];
}
for (var nxt : g[i]) {
int j = nxt[0], w = nxt[1];
if (j != p[i]) {
p[j] = i;
cnt[j] = cnt[i].clone();
cnt[j][w]++;
depth[j] = depth[i] + 1;
q.offer(j);
}
}
}
int k = queries.length;
int[] ans = new int[k];
for (int i = 0; i < k; ++i) {
int u = queries[i][0], v = queries[i][1];
int x = u, y = v;
if (depth[x] < depth[y]) {
int t = x;
x = y;
y = t;
}
for (int j = m - 1; j >= 0; --j) {
if (depth[x] - depth[y] >= (1 << j)) {
x = f[x][j];
}
}
for (int j = m - 1; j >= 0; --j) {
if (f[x][j] != f[y][j]) {
x = f[x][j];
y = f[y][j];
}
}
if (x != y) {
x = p[x];
}
int mx = 0;
for (int j = 0; j < 26; ++j) {
mx = Math.max(mx, cnt[u][j] + cnt[v][j] - 2 * cnt[x][j]);
}
ans[i] = depth[u] + depth[v] - 2 * depth[x] - mx;
}
return ans;
}
}
```

### **C++**

```cpp

class Solution {
public:
vector<int> minOperationsQueries(int n, vector<vector<int>>& edges, vector<vector<int>>& queries) {
int m = 32 - __builtin_clz(n);
vector<pair<int, int>> g[n];
int f[n][m];
int p[n];
int cnt[n][26];
int depth[n];
memset(f, 0, sizeof(f));
memset(cnt, 0, sizeof(cnt));
memset(depth, 0, sizeof(depth));
memset(p, 0, sizeof(p));
for (auto& e : edges) {
int u = e[0], v = e[1], w = e[2] - 1;
g[u].emplace_back(v, w);
g[v].emplace_back(u, w);
}
queue<int> q;
q.push(0);
while (!q.empty()) {
int i = q.front();
q.pop();
f[i][0] = p[i];
for (int j = 1; j < m; ++j) {
f[i][j] = f[f[i][j - 1]][j - 1];
}
for (auto& [j, w] : g[i]) {
if (j != p[i]) {
p[j] = i;
memcpy(cnt[j], cnt[i], sizeof(cnt[i]));
cnt[j][w]++;
depth[j] = depth[i] + 1;
q.push(j);
}
}
}
vector<int> ans;
for (auto& qq : queries) {
int u = qq[0], v = qq[1];
int x = u, y = v;
if (depth[x] < depth[y]) {
swap(x, y);
}
for (int j = m - 1; ~j; --j) {
if (depth[x] - depth[y] >= (1 << j)) {
x = f[x][j];
}
}
for (int j = m - 1; ~j; --j) {
if (f[x][j] != f[y][j]) {
x = f[x][j];
y = f[y][j];
}
}
if (x != y) {
x = p[x];
}
int mx = 0;
for (int j = 0; j < 26; ++j) {
mx = max(mx, cnt[u][j] + cnt[v][j] - 2 * cnt[x][j]);
}
ans.push_back(depth[u] + depth[v] - 2 * depth[x] - mx);
}
return ans;
}
};
```

### **Go**

```go

func minOperationsQueries(n int, edges [][]int, queries [][]int) []int {
m := bits.Len(uint(n))
g := make([][][2]int, n)
f := make([][]int, n)
for i := range f {
f[i] = make([]int, m)
}
p := make([]int, n)
cnt := make([][26]int, n)
cnt[0] = [26]int{}
depth := make([]int, n)
for _, e := range edges {
u, v, w := e[0], e[1], e[2]-1
g[u] = append(g[u], [2]int{v, w})
g[v] = append(g[v], [2]int{u, w})
}
q := []int{0}
for len(q) > 0 {
i := q[0]
q = q[1:]
f[i][0] = p[i]
for j := 1; j < m; j++ {
f[i][j] = f[f[i][j-1]][j-1]
}
for _, nxt := range g[i] {
j, w := nxt[0], nxt[1]
if j != p[i] {
p[j] = i
cnt[j] = [26]int{}
for k := 0; k < 26; k++ {
cnt[j][k] = cnt[i][k]
}
cnt[j][w]++
depth[j] = depth[i] + 1
q = append(q, j)
}
}
}
ans := make([]int, len(queries))
for i, qq := range queries {
u, v := qq[0], qq[1]
x, y := u, v
if depth[x] < depth[y] {
x, y = y, x
}
for j := m - 1; j >= 0; j-- {
if depth[x]-depth[y] >= (1 << j) {
x = f[x][j]
}
}
for j := m - 1; j >= 0; j-- {
if f[x][j] != f[y][j] {
x, y = f[x][j], f[y][j]
}
}
if x != y {
x = p[x]
}
mx := 0
for j := 0; j < 26; j++ {
mx = max(mx, cnt[u][j]+cnt[v][j]-2*cnt[x][j])
}
ans[i] = depth[u] + depth[v] - 2*depth[x] - mx
}
return ans
}

func max(a, b int) int {
if a > b {
return a
}
return b
}
```

### **...**
Expand Down
Loading