class TrieNode:
def __init__(self):
self.children = {}
self.count = 0
class Trie:
def __init__(self):
self.root = TrieNode()
self.L = 20 # Bit length, as n & val up to 10^5
def insert(self, num):
node = self.root
for i in reversed(range(self.L)):
bit = (num >> i) & 1
if bit not in node.children:
node.children[bit] = TrieNode()
node = node.children[bit]
node.count += 1
def remove(self, num):
node = self.root
for i in reversed(range(self.L)):
bit = (num >> i) & 1
node = node.children[bit]
node.count -= 1
def maxXor(self, num):
node = self.root
xor = 0
for i in reversed(range(self.L)):
bit = (num >> i) & 1
toggled = 1 - bit
if toggled in node.children and node.children[toggled].count > 0:
xor |= (1 << i)
node = node.children[toggled]
else:
node = node.children.get(bit, node)
return xor
class Solution:
def maxGeneticDifference(self, parents, queries):
from collections import defaultdict
n = len(parents)
tree = defaultdict(list)
root = -1
for child, p in enumerate(parents):
if p == -1:
root = child
else:
tree[p].append(child)
qmap = defaultdict(list)
for idx, (node, val) in enumerate(queries):
qmap[node].append((val, idx))
ans = [0] * len(queries)
trie = Trie()
def dfs(u):
trie.insert(u)
for val, idx in qmap[u]:
ans[idx] = trie.maxXor(val)
for v in tree[u]:
dfs(v)
trie.remove(u)
dfs(root)
return ans
class TrieNode {
public:
TrieNode* children[2];
int count;
TrieNode() : count(0) {
children[0] = children[1] = nullptr;
}
};
class Trie {
public:
TrieNode* root;
int L;
Trie() {
root = new TrieNode();
L = 20;
}
void insert(int num) {
TrieNode* node = root;
for (int i = L - 1; i >= 0; --i) {
int bit = (num >> i) & 1;
if (!node->children[bit])
node->children[bit] = new TrieNode();
node = node->children[bit];
node->count++;
}
}
void remove(int num) {
TrieNode* node = root;
for (int i = L - 1; i >= 0; --i) {
int bit = (num >> i) & 1;
node = node->children[bit];
node->count--;
}
}
int maxXor(int num) {
TrieNode* node = root;
int xorVal = 0;
for (int i = L - 1; i >= 0; --i) {
int bit = (num >> i) & 1;
int toggled = 1 - bit;
if (node->children[toggled] && node->children[toggled]->count > 0) {
xorVal |= (1 << i);
node = node->children[toggled];
} else {
node = node->children[bit];
}
}
return xorVal;
}
};
class Solution {
public:
vector maxGeneticDifference(vector& parents, vector>& queries) {
int n = parents.size();
vector> tree(n);
int root = -1;
for (int i = 0; i < n; ++i) {
if (parents[i] == -1) root = i;
else tree[parents[i]].push_back(i);
}
unordered_map>> qmap;
for (int i = 0; i < queries.size(); ++i) {
qmap[queries[i][0]].emplace_back(queries[i][1], i);
}
vector ans(queries.size());
Trie trie;
function dfs = [&](int u) {
trie.insert(u);
for (auto& q : qmap[u]) {
ans[q.second] = trie.maxXor(q.first);
}
for (int v : tree[u]) dfs(v);
trie.remove(u);
};
dfs(root);
return ans;
}
};
class TrieNode {
TrieNode[] children = new TrieNode[2];
int count = 0;
}
class Trie {
TrieNode root = new TrieNode();
int L = 20;
void insert(int num) {
TrieNode node = root;
for (int i = L - 1; i >= 0; --i) {
int bit = (num >> i) & 1;
if (node.children[bit] == null)
node.children[bit] = new TrieNode();
node = node.children[bit];
node.count++;
}
}
void remove(int num) {
TrieNode node = root;
for (int i = L - 1; i >= 0; --i) {
int bit = (num >> i) & 1;
node = node.children[bit];
node.count--;
}
}
int maxXor(int num) {
TrieNode node = root;
int xorVal = 0;
for (int i = L - 1; i >= 0; --i) {
int bit = (num >> i) & 1;
int toggled = 1 - bit;
if (node.children[toggled] != null && node.children[toggled].count > 0) {
xorVal |= (1 << i);
node = node.children[toggled];
} else {
node = node.children[bit];
}
}
return xorVal;
}
}
class Solution {
public int[] maxGeneticDifference(int[] parents, int[][] queries) {
int n = parents.length;
List[] tree = new ArrayList[n];
for (int i = 0; i < n; i++) tree[i] = new ArrayList<>();
int root = -1;
for (int i = 0; i < n; i++) {
if (parents[i] == -1) root = i;
else tree[parents[i]].add(i);
}
Map> qmap = new HashMap<>();
for (int i = 0; i < queries.length; i++) {
qmap.computeIfAbsent(queries[i][0], k -> new ArrayList<>()).add(new int[]{queries[i][1], i});
}
int[] ans = new int[queries.length];
Trie trie = new Trie();
dfs(root, tree, qmap, trie, ans);
return ans;
}
void dfs(int u, List[] tree, Map> qmap, Trie trie, int[] ans) {
trie.insert(u);
if (qmap.containsKey(u)) {
for (int[] q : qmap.get(u)) {
ans[q[1]] = trie.maxXor(q[0]);
}
}
for (int v : tree[u]) dfs(v, tree, qmap, trie, ans);
trie.remove(u);
}
}
class TrieNode {
constructor() {
this.children = {};
this.count = 0;
}
}
class Trie {
constructor() {
this.root = new TrieNode();
this.L = 20;
}
insert(num) {
let node = this.root;
for (let i = this.L - 1; i >= 0; --i) {
let bit = (num >> i) & 1;
if (!(bit in node.children))
node.children[bit] = new TrieNode();
node = node.children[bit];
node.count++;
}
}
remove(num) {
let node = this.root;
for (let i = this.L - 1; i >= 0; --i) {
let bit = (num >> i) & 1;
node = node.children[bit];
node.count--;
}
}
maxXor(num) {
let node = this.root;
let xor = 0;
for (let i = this.L - 1; i >= 0; --i) {
let bit = (num >> i) & 1;
let toggled = 1 - bit;
if (toggled in node.children && node.children[toggled].count > 0) {
xor |= (1 << i);
node = node.children[toggled];
} else {
node = node.children[bit];
}
}
return xor;
}
}
var maxGeneticDifference = function(parents, queries) {
const n = parents.length;
const tree = Array.from({length: n}, () => []);
let root = -1;
for (let i = 0; i < n; ++i) {
if (parents[i] === -1) root = i;
else tree[parents[i]].push(i);
}
const qmap = {};
for (let i = 0; i < queries.length; ++i) {
let [node, val] = queries[i];
if (!(node in qmap)) qmap[node] = [];
qmap[node].push([val, i]);
}
const ans = Array(queries.length);
const trie = new Trie();
function dfs(u) {
trie.insert(u);
if (qmap[u]) {
for (const [val, idx] of qmap[u]) {
ans[idx] = trie.maxXor(val);
}
}
for (const v of tree[u]) dfs(v);
trie.remove(u);
}
dfs(root);
return ans;
};
parents
(where parents[i]
is the parent of node i
, and -1
means node i
is the root), you are given several queries. Each query is a pair [node, val]
.
For each query, you must find the maximum value of val XOR x
for any ancestor x
of node
(including node
itself as its own ancestor). Return an array where the i
th element is the answer to the i
th query.
Constraints:
node
is a node index in the tree.val
is an integer value.node
to the root, collecting all ancestors, and for each, compute val XOR ancestor
, keeping the maximum. But this is too slow for large trees and many queries, since each query could take O(tree height) time.
We need a way to efficiently, for each query, find the ancestor (including the node itself) whose value gives the maximum XOR with val
. This is a classic "maximum XOR" problem, but restricted to the set of ancestors on the path from the root to the current node.
The key insight is to process queries as we traverse the tree. As we go down the tree, we can keep track of the current path's node values (ancestors) in a data structure that allows fast maximum XOR queries, such as a Trie (prefix tree). For each query at a node, we can ask the Trie for the best XOR with val
among all current ancestors.
parents
array, storing children for each node.
val XOR ancestor
.parents = [-1, 0, 0, 1, 1, 2]
(root is 0)queries = [[3, 5], [5, 2], [4, 6]]