XOR Queries on a given set

Given a set S with the initial element 0 that is S = { 0 }. The task is to perform each query when Q number of queries are given and print the answer after every query of type 3.
We can perform three types of query operations:

  • 1 X: We can add X to the set S.
  • 2 Y: For each element i, perform i ⊕ Y.
  • 3: Find the minimum element of the set.

Examples:

Input: Q = 10,
3
1 7
3
2 4
2 8
2 3
1 10
1 3
3
2 1
Output: 0 0 3

Explanation:
For the given 10 queries, the changes in the set for each query is as follows:



  1. The minimum is 0.
  2. The number 7 added to S –> {0, 7}.
  3. The minimum is still 0.
  4. All of the numbers in S are changed to their xor with 4 –> {4, 3}.
  5. All of the numbers in S are changed to their xor with 8 –> {12, 11}.
  6. All of the numbers in S are changed to their xor with 3 –> {15, 8}.
  7. The number 10 added to S –> {15, 8 ,10}.
  8. The number 3 added to S –> {15, 8, 10, 3}.
  9. The minimum is now 3.
  10. All of the numbers in S are changed to their xor with 1 –> {14, 9, 11, 2}.

Input: Q = 6
3
1 7
3
1 4
2 8
3
Output: 0 0 8

Prerequisite: Trie.

Approach:

We will try to solve this problem by using the trie approach of Minimum XOR Value Pair Problem.

  • So, In this problem, we have a binary trie and an integer x, we have to find the minimum value of XOR(x, y) where y is some integer from the trie.
  • Now, To solve this problem we will go down the trie from the most significant bit to the least.
  • Suppose we are at ith bit:
    If x[i] is 1, we will go down the path of the trie which has 1.
    If x[i] is 0, we will go down the path which has 0.
    If at position i, we do not have a branch to go down x[i], we will go the other way.

Now, coming to our problem.

  • Suppose we have inserted a1, a2, a3 in the set and then xor everything with x1, x2, x3, then it is same as XOR-ing with X = XOR(x1, x2, x3).
  • So, finding the minimum element is equivalent to finding the minimum among (a1, a2, a3) after XOR-ing with X.
    We have already noticed how to do that in the beginning.
  • Now, How to answer each of the queries.
    Let x = XOR(x1, x2, ….., xn), where x1, x2, …, xn are all numbers asked to XOR with the element of the set S.

    1. For Query 2, XOR with xi.
      we will not XOR every element in the trie with xi. instead, we will just update x = XOR(x, xi)
    2. For Query 3, getting the minimum element.
      We were supposed to have XOR-ed the entire array so far with X.
      So, now we will just calculate the minimum value obtained by taking XOR of all the elements in the set with X by using the above-mentioned approach.
    3. For Query 1, insert ai.
      We will not insert ai into the trie, but XOR(ai, x). Reason:

      • Suppose we Insert a1, a2, then XOR with x1, then insert a3, then XOR with x2.
      • When we query for minimum now, we will find the minimum value in : {XOR(a1, x1, x2), XOR(a2, x1, x2), XOR(a3, x1, x2)}
        But a3 has only been XOR-ed with x2 and not x1.
      • So it is critical that at every moment in time that we insert an element ai into the trie, we insert XOR(ai, x). This ensures that when we calculate the minimum, it will cancel out the previous XORs.
        So, in our example, our trie will contain
        {a1, a2, XOR(a3, x1)}.
      • When we query the minimum value of XOR(x), we will be finding the minimum using above method of {XOR(a1, x1, x2), XOR(a2, x1, x2), XOR(a3, x2)}, which is what we want. Inserting XOR(ai, x) will ensure that whatever we do the minimum operation, we do not do any unnecessary XORs on any ai.

Below is the C++ implementation of this approach:

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to operate 
// queries in a given set
#include <bits/stdc++.h>
using namespace std;
  
const int Maxbits = 30;
  
// Function for Query 1
void Insert(int x, int curx, 
            int* sz, int trie[100][2])
{
    // XOR each element before
    // storing it in the trie.
    x = x ^ curx;
    int p = 0;
  
    // Storing xored element in the trie.
    for (int i = Maxbits - 1; i >= 0; i--)
    {
        if (!trie[p][x >> i & 1])
            trie[p][x >> i & 1] = (*sz)++;
  
        p = trie[p][x >> i & 1];
    }
}
  
// Function for Query 2
void XorQuery(int x, int* curx)
{
    // Simply xor-ing all the number which
    // was asked to xor with the set elements.
    (*curx) = (*curx) ^ x;
}
  
// Function for Query 3
void MinXor(int x, int trie[100][2])
{
    int ans = 0, p = 0;
  
    // Finding the minimum element by checking 
    // if x[i] bit is same with trie element.
    for (int i = Maxbits - 1; i >= 0; i--) 
    {
        bool Currbit = (x >> i & 1);
  
        if (trie[p][Currbit])
            p = trie[p][Currbit];
  
        else {
            p = trie[p][!Currbit];
            ans |= 1 << i;
        }
    }
  
    cout << ans << endl;
}
  
// Driver code
int main()
{
    int sz = 1;
    int curx = 0;
    int trie[100][2] = { 0 };
  
    // Initialising the trie
    Insert(0, 0, &sz, trie);
  
    // Calling the Query
    MinXor(curx, trie);
    Insert(7, curx, &sz, trie);
    MinXor(curx, trie);
    XorQuery(4, &curx);
    XorQuery(8, &curx);
    XorQuery(3, &curx);
    Insert(10, curx, &sz, trie);
    Insert(3, curx, &sz, trie);
    MinXor(curx, trie);
    XorQuery(1, &curx);
  
    return 0;
}

chevron_right


Output:

0
0
3

Don’t stop now and take your learning to the next level. Learn all the important concepts of Data Structures and Algorithms with the help of the most trusted course: DSA Self Paced. Become industry ready at a student-friendly price.




My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.