Problem Description
Given a rooted tree where every node's label (from 0 to n - 1) also represents its unique genetic value, we are asked to handle multiple queries. Each query is in the form [node, val] and asks for the maximum value of (val XOR p) computed over every node p on the path from the given node to the root (inclusive). The tree is given via an array "parents", where parents[i] is the parent of node i (with the root having parents[root] == -1).
Key Insights
- The tree is static but the queries are on different root-to-node paths.
- A depth-first search (DFS) can be used to traverse the tree. We can "add" a node's value when entering it and "remove" it when backtracking.
- A bitwise trie (prefix tree) is an efficient data structure to compute maximum XOR of a given number with the set of stored numbers.
- Each DFS path simulates the current ancestors of a node, so queries anchored at that node can be answered via the current trie.
- The trie must support insertion and removal to correctly maintain the current path's values.
Space and Time Complexity
Time Complexity: O((n + q) * B) where B is the number of bits needed (≈ 18-20), since each insertion, removal, and query operation on the trie costs O(B).
Space Complexity: O(n * B) in the worst case due to storage in the trie (in practice, the number of nodes in the trie is at most B * (nodes in path)).
Solution
We execute a DFS from the root of the tree while maintaining a bitwise trie that holds the genetic values of the current path (from root to the current node). When processing a node, we:
- Insert its value into the trie.
- Answer all queries related to this node by computing the maximum XOR of the query value with the values currently in the trie.
- Recursively DFS into its children.
- Remove its value from the trie as we backtrack.
The bitwise trie is implemented as a binary tree where each node has at most two children corresponding to bits 0 and 1. Insertion and removal work bit-by-bit (from the most significant bit to the least). The maximum XOR query chooses the opposite bit if available at each level to maximize the result.