class Solution {
public:
vector<int> maxGeneticDifference(vector<int>& parents, vector<vector<int>>& queries) {
}
};
1938. 查询最大基因差
给你一棵 n
个节点的有根树,节点编号从 0
到 n - 1
。每个节点的编号表示这个节点的 独一无二的基因值 (也就是说节点 x
的基因值为 x
)。两个基因值的 基因差 是两者的 异或和 。给你整数数组 parents
,其中 parents[i]
是节点 i
的父节点。如果节点 x
是树的 根 ,那么 parents[x] == -1
。
给你查询数组 queries
,其中 queries[i] = [nodei, vali]
。对于查询 i
,请你找到 vali
和 pi
的 最大基因差 ,其中 pi
是节点 nodei
到根之间的任意节点(包含 nodei
和根节点)。更正式的,你想要最大化 vali XOR pi
。
请你返回数组 ans
,其中 ans[i]
是第 i
个查询的答案。
示例 1:
输入:parents = [-1,0,1,1], queries = [[0,2],[3,2],[2,5]] 输出:[2,3,7] 解释:查询数组处理如下: - [0,2]:最大基因差的对应节点为 0 ,基因差为 2 XOR 0 = 2 。 - [3,2]:最大基因差的对应节点为 1 ,基因差为 2 XOR 1 = 3 。 - [2,5]:最大基因差的对应节点为 2 ,基因差为 5 XOR 2 = 7 。
示例 2:
输入:parents = [3,7,-1,2,0,7,0,2], queries = [[4,6],[1,15],[0,5]] 输出:[6,14,7] 解释:查询数组处理如下: - [4,6]:最大基因差的对应节点为 0 ,基因差为 6 XOR 0 = 6 。 - [1,15]:最大基因差的对应节点为 1 ,基因差为 15 XOR 1 = 14 。 - [0,5]:最大基因差的对应节点为 2 ,基因差为 5 XOR 2 = 7 。
提示:
2 <= parents.length <= 105
i
,有 0 <= parents[i] <= parents.length - 1
。parents[root] == -1
1 <= queries.length <= 3 * 104
0 <= nodei <= parents.length - 1
0 <= vali <= 2 * 105
原站题解
python3 解法, 执行用时: 6984 ms, 内存消耗: 236.3 MB, 提交时间: 2023-08-22 15:19:49
# 离线算法 + 字典树 class Trie: left: "Trie" = None right: "Trie" = None # 由于我们的字典树需要支持删除数的操作 # 因此这里使用 cnt 变量进行记录该节点对应的数的个数 cnt: int = 0 class Solution: # 最大的数的二进制表示不会超过 18 位 # 那么二进制位的下标范围为 [0, 17] MAXD = 17 def maxGeneticDifference(self, parents: List[int], queries: List[List[int]]) -> List[int]: n = len(parents) # 将 parents 存储为树的形式,方便进行深度优先遍历 edges = defaultdict(list) # 找出根节点 root = -1 for i, parent in enumerate(parents): if parent == -1: root = i else: edges[parent].append(i) q = len(queries) # 使用离线的思想,stored[i] 存储了所有节点 i 对应的询问 stored = defaultdict(list) ans = [0] * q for i, (node, val) in enumerate(queries): stored[node].append((i, val)) r = Trie() # 向字典树添加一个数 def trie_insert(x: int) -> None: cur = r for i in range(Solution.MAXD, -1, -1): if x & (1 << i): if not cur.right: cur.right = Trie() cur = cur.right else: if not cur.left: cur.left = Trie() cur = cur.left cur.cnt += 1 # 对于给定的 x,返回字典树中包含的数与 x 进行异或运算可以达到的最大值 def trie_query(x: int) -> int: cur, ret = r, 0 for i in range(Solution.MAXD, -1, -1): if x & (1 << i): if cur.left and cur.left.cnt: ret |= (1 << i) cur = cur.left else: cur = cur.right else: if cur.right and cur.right.cnt: ret |= (1 << i) cur = cur.right else: cur = cur.left return ret # 从字典树中删除一个数 def trie_erase(x: int) -> None: cur = r for i in range(Solution.MAXD, -1, -1): if x & (1 << i): cur = cur.right else: cur = cur.left cur.cnt -= 1 # 深度优先遍历 def dfs(u: int) -> None: trie_insert(u) for idx, num in stored[u]: ans[idx] = trie_query(num) for v in edges[u]: dfs(v) trie_erase(u) dfs(root) return ans
golang 解法, 执行用时: 404 ms, 内存消耗: 72.2 MB, 提交时间: 2023-08-22 15:18:29
/** * 首先离线询问,将询问按照 nodei 分组。 * 然后根据 parents 建树,从根开始 DFS,每访问一个节点 v,就将其插入字典树, * 然后回答当前节点 v 对应的所有询问,最后在递归结束时将 v 从字典树中删去。 */ type node struct { son [2]*node cnt int } type trie struct{ root *node } func (t *trie) put(v int) *node { o := t.root for i := 17; i >= 0; i-- { b := v >> i & 1 if o.son[b] == nil { o.son[b] = &node{} } o = o.son[b] o.cnt++ } return o } func (t *trie) del(v int) *node { o := t.root for i := 17; i >= 0; i-- { o = o.son[v>>i&1] o.cnt-- // 删除操作只需要减少 cnt 就行,cnt 为 0 就视作删掉了该节点 } return o } func (t *trie) maxXor(v int) (ans int) { o := t.root for i := 17; i >= 0; i-- { b := v >> i & 1 if o.son[b^1] != nil && o.son[b^1].cnt > 0 { ans |= 1 << i b ^= 1 } o = o.son[b] } return } func maxGeneticDifference(parents []int, queries [][]int) []int { n := len(parents) // 建树 g := make([][]int, n) var root int for v, pa := range parents { if pa == -1 { root = v } else { g[pa] = append(g[pa], v) } } // 离线,将查询分组 type query struct{ val, i int } qs := make([][]query, n) for i, q := range queries { qs[q[0]] = append(qs[q[0]], query{q[1], i}) } ans := make([]int, len(queries)) t := &trie{&node{}} // 遍历整棵树,每访问一个节点就将其插入 trie 树,访问结束时将其从 trie 中删去 var dfs func(int) dfs = func(v int) { t.put(v) for _, q := range qs[v] { ans[q.i] = t.maxXor(q.val) } for _, w := range g[v] { dfs(w) } t.del(v) } dfs(root) return ans }