class TrieNode {
  public TrieNode[] children = new TrieNode[2];
  public int count = 0;
}
class Trie {
  public void update(int num, int val) {
    TrieNode node = root;
    for (int i = HEIGHT; i >= 0; --i) {
      final int bit = (num >> i) & 1;
      if (node.children[bit] == null)
        node.children[bit] = new TrieNode();
      node = node.children[bit];
      node.count += val;
    }
  }
  public int query(int num) {
    int ans = 0;
    TrieNode node = root;
    for (int i = HEIGHT; i >= 0; --i) {
      final int bit = (num >> i) & 1;
      final int targetBit = bit ^ 1;
      if (node.children[targetBit] != null && node.children[targetBit].count > 0) {
        ans += 1 << i;
        node = node.children[targetBit];
      } else {
        node = node.children[targetBit ^ 1];
      }
    }
    return ans;
  }
  private static final int HEIGHT = 17;
  TrieNode root = new TrieNode();
}
class Solution {
  public int[] maxGeneticDifference(int[] parents, int[][] queries) {
    final int n = parents.length;
    int[] ans = new int[queries.length];
    int rootVal = -1;
    List<Integer>[] tree = new List[n];
    for (int i = 0; i < n; ++i)
      tree[i] = new ArrayList<>();
    // {node: (index, val)}
    Map<Integer, List<Pair<Integer, Integer>>> nodeToQueries = new HashMap<>();
    Trie trie = new Trie();
    for (int i = 0; i < parents.length; ++i)
      if (parents[i] == -1)
        rootVal = i;
      else
        tree[parents[i]].add(i);
    for (int i = 0; i < queries.length; ++i) {
      final int node = queries[i][0];
      final int val = queries[i][1];
      nodeToQueries.putIfAbsent(node, new ArrayList<>());
      nodeToQueries.get(node).add(new Pair<>(i, val));
    }
    dfs(rootVal, trie, tree, nodeToQueries, ans);
    return ans;
  }
  private void dfs(int node, Trie trie, List<Integer>[] tree,
                   Map<Integer, List<Pair<Integer, Integer>>> nodeToQueries, int[] ans) {
    trie.update(node, 1);
    if (nodeToQueries.containsKey(node))
      for (Pair<Integer, Integer> query : nodeToQueries.get(node)) {
        final int i = query.getKey();
        final int val = query.getValue();
        ans[i] = trie.query(val);
      }
    for (final int child : tree[node])
      dfs(child, trie, tree, nodeToQueries, ans);
    trie.update(node, -1);
  }
}