Maximum XOR With an Element From Array

hard trie bitwise offline queries

Problem

You are given an array nums of non-negative integers and a list of queries, each a pair (x, m). For every query, choose the element v of nums with v ≤ m that maximizes x XOR v and report that XOR value; if every element exceeds m, the answer is -1. Answers must be returned in the original query order. Both arrays can hold up to 10⁵ entries with values up to 10⁹, so scanning all of nums for each query is too slow.

Inputnums = [0,1,2,3,4], queries = [[3,1],[1,3],[5,6]]
Output[3,3,7]
For (3,1) only 0 and 1 qualify and 3⊕0=3 wins; for (5,6) every element qualifies and 5⊕2=7 is the maximum.

def maximize_xor(nums, queries):
    nums.sort()
    order = sorted(range(len(queries)), key=lambda i: queries[i][1])
    ans = [-1] * len(queries)
    trie = {}
    j = 0
    for i in order:
        x, limit = queries[i]
        while j < len(nums) and nums[j] <= limit:
            node = trie
            for b in range(29, -1, -1):
                bit = (nums[j] >> b) & 1
                node = node.setdefault(bit, {})
            j += 1
        if not trie:
            continue
        best, node = 0, trie
        for b in range(29, -1, -1):
            want = 1 - ((x >> b) & 1)
            if want in node:
                best |= 1 << b
                node = node[want]
            else:
                node = node[1 - want]
        ans[i] = best
    return ans
function maximizeXor(nums, queries) {
  nums.sort((a, b) => a - b);
  const order = queries.map((q, i) => i).sort((a, b) => queries[a][1] - queries[b][1]);
  const ans = new Array(queries.length).fill(-1);
  const trie = {};
  let j = 0;
  for (const i of order) {
    const [x, limit] = queries[i];
    while (j < nums.length && nums[j] <= limit) {
      let node = trie;
      for (let b = 29; b >= 0; b--) {
        const bit = (nums[j] >> b) & 1;
        node = node[bit] || (node[bit] = {});
      }
      j++;
    }
    if (j === 0) continue;
    let best = 0, node = trie;
    for (let b = 29; b >= 0; b--) {
      const want = 1 - ((x >> b) & 1);
      if (node[want]) { best |= 1 << b; node = node[want]; }
      else node = node[1 - want];
    }
    ans[i] = best;
  }
  return ans;
}
int[] maximizeXor(int[] nums, int[][] queries) {
    Arrays.sort(nums);
    Integer[] order = new Integer[queries.length];
    for (int i = 0; i < order.length; i++) order[i] = i;
    Arrays.sort(order, (a, b) -> queries[a][1] - queries[b][1]);
    int[] ans = new int[queries.length];
    int[][] ch = new int[nums.length * 30 + 1][2];
    int size = 1, j = 0;
    for (int i : order) {
        int x = queries[i][0], limit = queries[i][1];
        while (j < nums.length && nums[j] <= limit) {
            int node = 0;
            for (int b = 29; b >= 0; b--) {
                int bit = (nums[j] >> b) & 1;
                if (ch[node][bit] == 0) ch[node][bit] = size++;
                node = ch[node][bit];
            }
            j++;
        }
        if (j == 0) { ans[i] = -1; continue; }
        int best = 0, node = 0;
        for (int b = 29; b >= 0; b--) {
            int want = 1 - ((x >> b) & 1);
            if (ch[node][want] != 0) { best |= 1 << b; node = ch[node][want]; }
            else node = ch[node][1 - want];
        }
        ans[i] = best;
    }
    return ans;
}
vector<int> maximizeXor(vector<int>& nums, vector<vector<int>>& queries) {
    sort(nums.begin(), nums.end());
    vector<int> order(queries.size()), ans(queries.size(), -1);
    iota(order.begin(), order.end(), 0);
    sort(order.begin(), order.end(),
         [&](int a, int b) { return queries[a][1] < queries[b][1]; });
    vector<array<int, 2>> ch(1, {0, 0});
    int j = 0;
    for (int i : order) {
        int x = queries[i][0], limit = queries[i][1];
        while (j < (int)nums.size() && nums[j] <= limit) {
            int node = 0;
            for (int b = 29; b >= 0; b--) {
                int bit = (nums[j] >> b) & 1;
                if (!ch[node][bit]) { ch[node][bit] = ch.size(); ch.push_back({0, 0}); }
                node = ch[node][bit];
            }
            j++;
        }
        if (j == 0) continue;
        int best = 0, node = 0;
        for (int b = 29; b >= 0; b--) {
            int want = 1 - ((x >> b) & 1);
            if (ch[node][want]) { best |= 1 << b; node = ch[node][want]; }
            else node = ch[node][1 - want];
        }
        ans[i] = best;
    }
    return ans;
}
Time: O(n log n + q log q + 30(n + q)) Space: O(30n)