public: vector<int> maxGeneticDifference(vector<int>& parents, vector<vector<int>>& queries){ int n = parents.size();
// 将 parents 存储为树的形式,方便进行深度优先遍历 vector<vector<int>> edges(n); // 找出根节点 int root = -1; for (int i = 0; i < n; ++i) { if (parents[i] == -1) { root = i; } else { edges[parents[i]].push_back(i); } }
int q = queries.size(); // 使用离线的思想,stored[i] 存储了所有节点 i 对应的询问 vector<vector<pair<int, int>>> stored(n); vector<int> ans(q); for (int i = 0; i < q; ++i) { stored[queries[i][0]].emplace_back(i, queries[i][1]); }
Trie* r = newTrie();
// 向字典树添加一个数 auto trie_insert = [&](int x) { Trie* cur = r; for (int i = MAXD; i >= 0; --i) { if (x & (1 << i)) { if (!cur->right) { cur->right = newTrie(); } cur = cur->right; } else { if (!cur->left) { cur->left = newTrie(); } cur = cur->left; } ++cur->cnt; } };
// 对于给定的 x,返回字典树中包含的数与 x 进行异或运算可以达到的最大值 auto trie_query = [&](int x) -> int { int ret = 0; Trie* cur = r; for (int i = MAXD; i >= 0; --i) { if (x & (1 << i)) { if (cur->left && cur->left->cnt) { ret |= (1 << i); cur = cur->left; } else { cur = cur->right; } } else { if (cur->right && cur->right->cnt) { ret |= (1 << i); cur = cur->right; } else { cur = cur->left; } } } return ret; };
// 从字典树中删除一个数 auto trie_erase = [&](int x) { Trie* cur = r; for (int i = MAXD; i >= 0; --i) { if (x & (1 << i)) { cur = cur->right; } else { cur = cur->left; } --cur->cnt; } };
defmaxGeneticDifference(self, parents: List[int], queries: List[List[int]]) -> List[int]: n = len(parents)
# 将 parents 存储为树的形式,方便进行深度优先遍历 edges = defaultdict(list) # 找出根节点 root = -1 for i, parent inenumerate(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) inenumerate(queries): stored[node].append((i, val))
r = Trie()
# 向字典树添加一个数 deftrie_insert(x: int) -> None: cur = r for i inrange(Solution.MAXD, -1, -1): if x & (1 << i): ifnot cur.right: cur.right = Trie() cur = cur.right else: ifnot cur.left: cur.left = Trie() cur = cur.left cur.cnt += 1
# 对于给定的 x,返回字典树中包含的数与 x 进行异或运算可以达到的最大值 deftrie_query(x: int) -> int: cur, ret = r, 0 for i inrange(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
# 从字典树中删除一个数 deftrie_erase(x: int) -> None: cur = r for i inrange(Solution.MAXD, -1, -1): if x & (1 << i): cur = cur.right else: cur = cur.left cur.cnt -= 1
# 深度优先遍历 defdfs(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
复杂度分析
时间复杂度:O((n+q) \log C),其中 q 是数组 queries 的长度,\log C = 18 是本题中最大的数的二进制表示的位数。在深度优先遍历的过程中,访问的节点个数为 n,每个节点需要 O(\log C) 的时间在一开将其加入字典树以及回溯前将其从字典树中移除。对于数组 queries 中的每一个询问,我们需要 O(\log C) 的时间得到答案。因此总时间复杂度为 O((n+q) \log C)。
空间复杂度:O(n\log C + q)。我们需要 O(n) 的空间存储树本身,O(n \log C) 的空间存储字典树,O(q) 的空间存储将询问进行离线,分配到每个节点上。