LC 6103. 从树中删除边的最小分数
https://leetcode.cn/contest/weekly-contest-299/problems/minimum-score-after-removals-on-a-tree/
这题目想了比较长的时间,觉得下面这个解法应该是正确的,大致思路就是枚举删除边。
问题就是,如果我们枚举删除边之后在去计算的话,那么时间复杂度肯定是不行的。边的数量在1000左右,枚举2个删除边就是1M的数据量级别,那么计算复杂度就应该是O(1),否则肯定会超时。
假设我们已经创建好了这个联通树,并且计算好了所有的XOR值,记为XOR(t). 我们准备删除 `b->a` 和 `d->c` 两条边,大约有下面几种情况
- 如果b是c的父亲节点的话,那么两个组件是 d 和 `c -> … b`. 两个组件的值分别是 `XOR(d)` 和 `XOR(b) ^ XOR(d)`
- 如果d是a的父亲节点的话,那么两个组件是 b 和 `a -> … d`. 两个组件的值分别是 `XOR(b)` 和 `XOR(d) ^ XOR(b)`
- 两个边是相互独立的话,那么两个组件是 b 和 d, 值分别是 `XOR(b)` 和 `XOR(d)`
有了两个组件,最后的组件就可以通过全值进行异或了。为了快速判断父亲节点,还需要保存每个节点的父节点情况。
#!/usr/bin/env python # coding:utf-8 # Copyright (C) dirlt from typing import List class TreeNode: def __init__(self, index, value, depth): self.index = index self.value = value self.total = value self.depth = depth self.parent = set() class Solution: def minimumScore(self, nums: List[int], edges: List[List[int]]) -> int: n = len(nums) adj = [[] for _ in range(n)] for x, y in edges: adj[x].append(y) adj[y].append(x) tt = 0 for x in nums: tt ^= x trees = [None] * n def build(x, d, pt): t = TreeNode(x, nums[x], d) pt.append(x) t.parent = set(pt) trees[x] = t for y in adj[x]: if trees[y]: continue t2 = build(y, d + 1, pt) t.total ^= t2.total pt.pop() return t build(0, 0, []) for xx in edges: xx.sort(key=lambda x: trees[x].depth) inf = 1 << 30 ans = inf for i in range(len(edges)): for j in range(i + 1, len(edges)): a, b = edges[i] c, d = edges[j] ta, tb, tc, td = [trees[x] for x in [a, b, c, d]] # tb -> ta # td -> tc if d in ta.parent: # tb -> ta -> ... td -> tc x = tb.total y = td.total ^ x elif b in tc.parent: # td -> tc -> tb -> ta x = td.total y = tb.total ^ x else: x = tb.total y = td.total z = tt ^ x ^ y minv = min(x, y, z) maxv = max(x, y, z) res = maxv - minv ans = min(res, ans) return ans