Open In App

XOR Queries on a given set

Improve
Improve
Like Article
Like
Save
Share
Report

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, 

1 7 

2 4 
2 8 
2 3 
1 10 
1 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 

1 7 

1 4 
2 8 

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 are the implementations of this approach:
 

CPP




// 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;
}


Java




//Java code for the above approach
import java.util.Scanner;
 
class GFG{
  static final int Maxbits = 30;
  static int sz = 1;
  static int curx = 0;
  static int[][] trie = new int[100][2];
 
  // Function for Query 1
  static void Insert(int x, int curx) {
    // 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] == 0)
        trie[p][x >> i & 1] = sz++;
 
      p = trie[p][x >> i & 1];
    }
  }
 
  // Function for Query 2
  static void XorQuery(int x) {
    // Simply xor-ing all the number which
    // was asked to xor with the set elements.
    curx = curx ^ x;
  }
 
  // Function for Query 3
  static void MinXor(int x) {
    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--) {
      boolean Currbit = (x >> i & 1) == 1;
 
      if (trie[p][Currbit ? 1 : 0] != 0)
        p = trie[p][Currbit ? 1 : 0];
      else {
        p = trie[p][Currbit ? 0 : 1];
        ans |= 1 << i;
      }
    }
 
    System.out.println(ans);
  }
 
  public static void main(String[] args) {
    // Initialising the trie
    Insert(0, 0);
 
    // Calling the Query
    MinXor(curx);
    Insert(7, curx);
    MinXor(curx);
    XorQuery(4);
    XorQuery(8);
    XorQuery(3);
    Insert(10, curx);
    Insert(3, curx);
    MinXor(curx);
    XorQuery(1);
  }
}
 
//This code is contributed by Potta Lokesh


Python3




# Python3 program to operate
# queries in a given set
 
Maxbits = 30
 
# Function for Query 1
 
 
def Insert(x, curx, trie):
    global sz
    # XOR each element before
    # storing it in the trie.
    x = x ^ curx
    p = 0
 
    # Storing xored element in the trie.
    for i in range(Maxbits - 1, -1, -1):
        if not(trie[p][x >> i & 1]):
            trie[p][x >> i & 1] = sz
            sz += 1
 
        p = trie[p][x >> i & 1]
 
 
# Function for Query 2
def XorQuery(x,):
    global curx
    # Simply xor-ing all the number which
    # was asked to xor with the set elements.
    curx ^= x
 
 
# Function for Query 3
def MinXor(x, trie):
    ans = 0
    p = 0
 
    # Finding the minimum element by checking
    # if x[i] bit is same with trie element.
    for i in range(Maxbits - 1, -1, -1):
        Currbit = (x >> i & 1)
 
        if (trie[p][Currbit]):
            p = trie[p][Currbit]
 
        else:
            p = trie[p][~Currbit]
            ans |= 1 << i
 
    print(ans)
 
 
# Driver code
if __name__ == '__main__':
    sz = 1
    curx = 0
    trie = [[0]*2 for _ in range(100)]
 
    # Initialising the trie
    Insert(0, 0, trie)
 
    # Calling the Query
    MinXor(curx, trie)
    Insert(7, curx, trie)
    MinXor(curx, trie)
    XorQuery(4, )
    XorQuery(8, )
    XorQuery(3, )
    Insert(10, curx, trie)
    Insert(3, curx,  trie)
    MinXor(curx, trie)
    XorQuery(1,)


C#




// C# code for the above approach
using System;
 
class GFG{
static int Maxbits = 30;
static int sz = 1;
static int curx = 0;
static int[,] trie = new int[100,2];
 
// Function for Query 1
static void Insert(int x, int curx)
{
   
    // 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] == 0)
        trie[p,x >> i & 1] = sz++;
 
    p = trie[p,x >> i & 1];
    }
}
 
// Function for Query 2
static void XorQuery(int x) {
    // Simply xor-ing all the number which
    // was asked to xor with the set elements.
    curx = curx ^ x;
}
 
// Function for Query 3
static void MinXor(int x) {
    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) == 1;
 
    if (trie[p,Currbit ? 1 : 0] != 0)
        p = trie[p,Currbit ? 1 : 0];
    else {
        p = trie[p,Currbit ? 0 : 1];
        ans |= 1 << i;
    }
    }
 
    Console.WriteLine(ans);
}
 
public static void Main() {
    // Initialising the trie
    Insert(0, 0);
 
    // Calling the Query
    MinXor(curx);
    Insert(7, curx);
    MinXor(curx);
    XorQuery(4);
    XorQuery(8);
    XorQuery(3);
    Insert(10, curx);
    Insert(3, curx);
    MinXor(curx);
    XorQuery(1);
}
}
 
// This code is contributed by Aman Kumar


Javascript




<script>
    //Javascript code for the above approach
     
    const Maxbits = 30;
    let sz = 1;
    let curx = 0;
    const trie = new Array(100).fill().map(() => new Array(2).fill(0));
     
    // Function for Query 1
    function Insert(x, curx) {
        // XOR each element before storing it in the trie.
        x = x ^ curx;
        let p = 0;
     
        // Storing xored element in the trie.
        for (let i = Maxbits - 1; i >= 0; i--) {
            if (trie[p][(x >> i) & 1] == 0)
                trie[p][(x >> i) & 1] = sz++;
     
            p = trie[p][(x >> i) & 1];
        }
    }
     
    // Function for Query 2
    function XorQuery(x) {
        // Simply xor-ing all the number which
        // was asked to xor with the set elements.
        curx = curx ^ x;
    }
     
    // Function for Query 3
    function MinXor(x) {
        let ans = 0, p = 0;
     
        // Finding the minimum element by checking
        // if x[i] bit is same with trie element.
        for (let i = Maxbits - 1; i >= 0; i--) {
            let Currbit = (x >> i) & 1;
     
            if (trie[p][Currbit ? 1 : 0] != 0)
                p = trie[p][Currbit ? 1 : 0];
            else {
                p = trie[p][Currbit ? 0 : 1];
                ans |= 1 << i;
            }
        }
     
        document.write(ans);
    }
     
    // Driver code
    Insert(0, 0);
     
    // Calling the Query
    MinXor(curx);
    Insert(7, curx);
    MinXor(curx);
    XorQuery(4);
    XorQuery(8);
    XorQuery(3);
    Insert(10, curx);
    Insert(3, curx);
    MinXor(curx);
    XorQuery(1);
     
    // This code is contributed by Utkarsh Kumar.
      
</script>


Output: 

0
0
3

 

Time Complexity: O(N) per query. Where N is the number of bits in the query element.
Auxiliary Space: O(N) 



Last Updated : 26 Feb, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads