class Trie:
    def __init__(self,):
        self.root = {}
    
    def insert(self,x):
        p = self.root
        for i in range(32)[::-1]:
            cur = (x>>i) & 1
            if cur not in p:
                p[cur] = {}
            p = p[cur]
            
    def query_max_XOR(self,x):
        res,p = 0, self.root
        if not p:
            return -1
        for i in range(32)[::-1]:
            cur = (x>>i)&1
            if 1-cur in p:
                p = p[1-cur]
                res |= (1<<i)
            else:
                p = p[cur]
        return res 
class Solution:
    def maximizeXor(self, A: List[int], queries: List[List[int]]) -> List[int]:
        """
        step1. trie, insert , find_max_xor
        step2. sort arr, resort query by max val m
        step3. loop each query target val x,  insert 
        step4. given valid candidates, call query() to get max 
        ???  why sort both arra and qury?  to avoid finding out of bounded value when searching best xor 
        """
        A.sort()
        #queries = sorted(enumerate(queries),key = lambda x: x[1][1]), then change args in for loop below 
        queries = sorted([(m,x,i) for i,(x,m) in enumerate(queries)]) # sort by value m  
        trie = Trie()
        res = [-1] * len(queries)
        for m,x,i in queries:
            j = 0
            while j < len(A) and A[j] <= m:
                # insert valid candidate in array A, here using set will not optimize performance since len(A) can be huge   
                trie.insert(A[j])
                j += 1 
            res[i] = trie.query_max_XOR(x)
        return res 

TODO: Trie W/O sort