Open In App

XOR of elements in a given range with updates using Fenwick Tree

Last Updated : 18 Apr, 2023
Comments
Improve
Suggest changes
Like Article
Like
Report

Given an array A[] of integers and array Q consisting of queries of the following two types:

  • (1, L, R) : Return XOR of all elements present between indices L and R.
  • (2, I, val) : update A[I] to A[I] XOR val.


The task is to solve each query and print the XOR for every Query of 1st type, using Fenwick Tree.
Examples:

Input: A[] = {2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9} 
Q = {{ 1, 3, 8}, {2, 4, 6}, {1, 3, 8}} 
Output : 
XOR of elements in range 3 to 8 is 5 
XOR of elements in range 3 to 8 is 3 
Explanation: 
XOR of subarray { 3, 2, 3, 4, 5, 6 } is 5. 
After 2nd query arr[4] gets replaced by 4. 
Xor of subarray { 3, 4, 3, 4, 5, 6 } is 3.
Input :A[] = {2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9} 
Q = {{1, 0, 9}, {2, 3, 6}, {2, 5, 5}, {2, 8, 1}, {1, 0, 9}} 
Output : 
XOR of elements in range 0 to 9 is 0 
XOR of elements in range 0 to 9 is 2


Approach:

  • For the query of type 1, return the Xor of elements in range [1, R] and range[1, L-1] using getXor().
  • In getXor(), For i starting from index to all its ancestors till 1, keep calculating XOR with BITree[i]. In order to get ancestor of i-th index in getXor() view, we just need to subtract LSB(least Significant Bit) from i by i = i - i&(-i). Finally return the final XOR value.
  • For query of type 2, update A[index] to A[index] ^ val. Update all ranges that include this element in BITree[] by calling updateBIT().
  • In updateBIT(), For every i starting from index to all its ancestors up to N, update BITree[i] as BITree[i] ^ val. In order to get ancestor of i-th index in updateBit() view, we just need to add LSB(least Significant Bit) from i by i = i + i&(-i).


Below is the implementation of the above approach:

C++
// C++ Program to find XOR of
// elements in given range [L, R].

#include <bits/stdc++.h>
using namespace std;

// Returns XOR of arr[0..index].
// This function assumes that the
// array is preprocessed and partial
// XORs of array elements are stored
// in BITree[].
int getXOR(int BITree[], int index)
{
    int ans = 0;
    index += 1;

    // Traverse ancestors
    // of BITree[index]
    while (index > 0) {

        // XOR current element
        // of BIT to ans
        ans ^= BITree[index];

        // Update index to that
        // of the parent node in
        // getXor() view by
        // subtracting LSB(Least
        // Significant Bit)
        index -= index & (-index);
    }
    return ans;
}

// Updates the Binary Index Tree by
// replacing all ancestors of index
// by their respective XOR with val
void updateBIT(int BITree[], int n,
               int index, int val)
{
    index = index + 1;

    // Traverse all ancestors
    // and XOR with 'val'.
    while (index <= n) {

        // XOR 'val' to current
        // node of BIT
        BITree[index] ^= val;

        // Update index to that
        // of the parent node in
        // updateBit() view by
        // adding LSB(Least
        // Significant Bit)
        index += index & (-index);
    }
}

// Constructs and returns a Binary
// Indexed Tree for the given array
int* constructBITree(int arr[], int n)
{
    // Create and initialize
    // the Binary Indexed Tree
    int* BITree = new int[n + 1];
    for (int i = 1; i <= n; i++)
        BITree[i] = 0;

    // Store the actual values in
    // BITree[] using update()
    for (int i = 0; i < n; i++)
        updateBIT(BITree, n, i, arr[i]);

    return BITree;
}

int rangeXor(int BITree[], int l, int r)
{
    return getXOR(BITree, r)
           ^ getXOR(BITree, l - 1);
}

// Driver Code
int main()
{
    int A[] = { 2, 1, 1, 3, 2, 3,
                4, 5, 6, 7, 8, 9 };
    int n = sizeof(A) / sizeof(A[0]);

    vector<vector<int> > q
        = { { 1, 0, 9 },
            { 2, 3, 6 },
            { 2, 5, 5 },
            { 2, 8, 1 },
            { 1, 0, 9 } };

    // Create the Binary Indexed Tree
    int* BITree = constructBITree(A, n);

    // Solve each query in Q
    for (int i = 0; i < q.size(); i++) {
        int id = q[i][0];

        if (id == 1) {
            int L = q[i][1];
            int R = q[i][2];
            cout << "XOR of elements "
                 << "in given range is "
                 << rangeXor(BITree, L, R)
                 << "\n";
        }
        else {
            int idx = q[i][1];
            int val = q[i][2];
            A[idx] ^= val;

            // Update the values of all
            // ancestors of idx
            updateBIT(BITree, n, idx, val);
        }
    }

    return 0;
}
Java
// Java Program to find XOR of
// elements in given range [L, R].
import java.util.*;

class GFG{

// Returns XOR of arr[0..index].
// This function assumes that the
// array is preprocessed and partial
// XORs of array elements are stored
// in BITree[].
static int getXOR(int BITree[], int index)
{
    int ans = 0;
    index += 1;

    // Traverse ancestors
    // of BITree[index]
    while (index > 0) 
    {

        // XOR current element
        // of BIT to ans
        ans ^= BITree[index];

        // Update index to that
        // of the parent node in
        // getXor() view by
        // subtracting LSB(Least
        // Significant Bit)
        index -= index & (-index);
    }
    return ans;
}

// Updates the Binary Index Tree by
// replacing all ancestors of index
// by their respective XOR with val
static void updateBIT(int BITree[], int n,
                      int index, int val)
{
    index = index + 1;

    // Traverse all ancestors
    // and XOR with 'val'.
    while (index <= n) 
    {

        // XOR 'val' to current
        // node of BIT
        BITree[index] ^= val;

        // Update index to that
        // of the parent node in
        // updateBit() view by
        // adding LSB(Least
        // Significant Bit)
        index += index & (-index);
    }
}

// Constructs and returns a Binary
// Indexed Tree for the given array
static int[] constructBITree(int arr[], int n)
{
    // Create and initialize
    // the Binary Indexed Tree
    int []BITree = new int[n + 1];
    for (int i = 1; i <= n; i++)
        BITree[i] = 0;

    // Store the actual values in
    // BITree[] using update()
    for (int i = 0; i < n; i++)
        updateBIT(BITree, n, i, arr[i]);

    return BITree;
}

static int rangeXor(int BITree[], int l, int r)
{
    return getXOR(BITree, r) ^ 
           getXOR(BITree, l - 1);
}

// Driver Code
public static void main(String[] args)
{
    int A[] = { 2, 1, 1, 3, 2, 3,
                4, 5, 6, 7, 8, 9 };
    int n = A.length;

    int [][]q = { { 1, 0, 9 },
                  { 2, 3, 6 },
                  { 2, 5, 5 },
                  { 2, 8, 1 },
                  { 1, 0, 9 } };

    // Create the Binary Indexed Tree
    int []BITree = constructBITree(A, n);

    // Solve each query in Q
    for (int i = 0; i < q.length; i++) 
    {
        int id = q[i][0];

        if (id == 1) 
        {
            int L = q[i][1];
            int R = q[i][2];
            System.out.print("XOR of elements " + 
                           "in given range is " + 
                         rangeXor(BITree, L, R) + "\n");
        }
        else 
        {
            int idx = q[i][1];
            int val = q[i][2];
            A[idx] ^= val;

            // Update the values of all
            // ancestors of idx
            updateBIT(BITree, n, idx, val);
        }
    }
}
}

// This code is contributed by Princi Singh
Python3
# Python3 program to find XOR of 
# elements in given range [L, R]. 

# Returns XOR of arr[0..index].
# This function assumes that the
# array is preprocessed and partial
# XORs of array elements are stored
# in BITree[].
def getXOR(BITree, index):

    ans = 0
    index += 1

    # Traverse ancestors
    # of BITree[index]
    while (index > 0):
    
        # XOR current element
        # of BIT to ans
        ans ^= BITree[index]

        # Update index to that
        # of the parent node in
        # getXor() view by
        # subtracting LSB(Least
        # Significant Bit)
        index -= index & (-index)
    
    return ans

# Updates the Binary Index Tree by
# replacing all ancestors of index
# by their respective XOR with val
def updateBIT(BITree, n, index, val):

    index = index + 1

    # Traverse all ancestors
    # and XOR with 'val'.
    while (index <= n):
    
        # XOR 'val' to current
        # node of BIT
        BITree[index] ^= val

        # Update index to that
        # of the parent node in
        # updateBit() view by
        # adding LSB(Least
        # Significant Bit)
        index += index & (-index)
    
# Constructs and returns a Binary
# Indexed Tree for the given array
def constructBITree(arr, n):

    # Create and initialize
    # the Binary Indexed Tree
    BITree = [0] * (n + 1)
    
    # Store the actual values in
    # BITree[] using update()
    for i in range(n):
        updateBIT(BITree, n, i, arr[i])

    return BITree

def rangeXor(BITree, l, r):

    return (getXOR(BITree, r) ^ 
            getXOR(BITree, l - 1))
           
# Driver Code
if __name__ == "__main__":
    
    A = [ 2, 1, 1, 3, 2, 3,
          4, 5, 6, 7, 8, 9 ]
    n = len(A) 

    q = [ [ 1, 0, 9 ], [ 2, 3, 6 ],
          [ 2, 5, 5 ], [ 2, 8, 1 ],
          [ 1, 0, 9 ] ]

    # Create the Binary Indexed Tree
    BITree = constructBITree(A, n)

    # Solve each query in Q
    for i in range(len(q)): 
        id = q[i][0]

        if (id == 1):
            L = q[i][1]
            R = q[i][2]
            print("XOR of elements in " 
                  "given range is ",
                  rangeXor(BITree, L, R))
        else:
            idx = q[i][1]
            val = q[i][2]
            A[idx] ^= val

            # Update the values of all
            # ancestors of idx
            updateBIT(BITree, n, idx, val)

# This code is contributed by jana_sayantan
C#
// C# program to find XOR of
// elements in given range [L, R].
using System;

class GFG{

// Returns XOR of arr[0..index].
// This function assumes that the
// array is preprocessed and partial
// XORs of array elements are stored
// in BITree[].
static int getXOR(int []BITree, int index)
{
    int ans = 0;
    index += 1;

    // Traverse ancestors
    // of BITree[index]
    while (index > 0) 
    {

        // XOR current element
        // of BIT to ans
        ans ^= BITree[index];

        // Update index to that
        // of the parent node in
        // getXor() view by
        // subtracting LSB(Least
        // Significant Bit)
        index -= index & (-index);
    }
    return ans;
}

// Updates the Binary Index Tree by
// replacing all ancestors of index
// by their respective XOR with val
static void updateBIT(int []BITree, int n,
                      int index, int val)
{
    index = index + 1;

    // Traverse all ancestors
    // and XOR with 'val'.
    while (index <= n) 
    {

        // XOR 'val' to current
        // node of BIT
        BITree[index] ^= val;

        // Update index to that
        // of the parent node in
        // updateBit() view by
        // adding LSB(Least
        // Significant Bit)
        index += index & (-index);
    }
}

// Constructs and returns a Binary
// Indexed Tree for the given array
static int[] constructBITree(int []arr, 
                             int n)
{
    
    // Create and initialize
    // the Binary Indexed Tree
    int []BITree = new int[n + 1];
    for(int i = 1; i <= n; i++)
       BITree[i] = 0;

    // Store the actual values in
    // BITree[] using update()
    for(int i = 0; i < n; i++)
       updateBIT(BITree, n, i, arr[i]);

    return BITree;
}

static int rangeXor(int []BITree, int l,
                                  int r)
{
    return getXOR(BITree, r) ^ 
           getXOR(BITree, l - 1);
}

// Driver Code
public static void Main(String[] args)
{
    int []A = { 2, 1, 1, 3, 2, 3,
                4, 5, 6, 7, 8, 9 };
    int n = A.Length;
    
    int [,]q = { { 1, 0, 9 },
                 { 2, 3, 6 },
                 { 2, 5, 5 },
                 { 2, 8, 1 },
                 { 1, 0, 9 } };

    // Create the Binary Indexed Tree
    int []BITree = constructBITree(A, n);

    // Solve each query in Q
    for(int i = 0; i < q.GetLength(0); i++) 
    {
       int id = q[i, 0];
       
       if (id == 1) 
       {
           int L = q[i, 1];
           int R = q[i, 2];
           Console.Write("XOR of elements " + 
                       "in given range is " + 
                     rangeXor(BITree, L, R) + "\n");
       }
       else
       {
           int idx = q[i, 1];
           int val = q[i, 2];
           A[idx] ^= val;
           
           // Update the values of 
           // all ancestors of idx
           updateBIT(BITree, n, idx, val);
       }
    }
}
}

// This code is contributed by sapnasingh4991
JavaScript
<script>

// Javascript Program to find XOR of
// elements in given range [L, R].

// Returns XOR of arr[0..index].
// This function assumes that the
// array is preprocessed and partial
// XORs of array elements are stored
// in BITree[].
function getXOR(BITree, index)
{
    let ans = 0;
    index += 1;

    // Traverse ancestors
    // of BITree[index]
    while (index > 0) {

        // XOR current element
        // of BIT to ans
        ans ^= BITree[index];

        // Update index to that
        // of the parent node in
        // getXor() view by
        // subtracting LSB(Least
        // Significant Bit)
        index -= index & (-index);
    }
    return ans;
}

// Updates the Binary Index Tree by
// replacing all ancestors of index
// by their respective XOR with val
function updateBIT(BITree, n, index, val)
{
    index = index + 1;

    // Traverse all ancestors
    // and XOR with 'val'.
    while (index <= n) {

        // XOR 'val' to current
        // node of BIT
        BITree[index] ^= val;

        // Update index to that
        // of the parent node in
        // updateBit() view by
        // adding LSB(Least
        // Significant Bit)
        index += index & (-index);
    }
}

// Constructs and returns a Binary
// Indexed Tree for the given array
function constructBITree(arr, n)
{
    // Create and initialize
    // the Binary Indexed Tree
    let BITree = new Array(n + 1);
    for (let i = 1; i <= n; i++)
        BITree[i] = 0;

    // Store the actual values in
    // BITree[] using update()
    for (let i = 0; i < n; i++)
        updateBIT(BITree, n, i, arr[i]);

    return BITree;
}

function rangeXor(BITree, l, r)
{
    return getXOR(BITree, r)
           ^ getXOR(BITree, l - 1);
}

// Driver Code
    let A = [ 2, 1, 1, 3, 2, 3,
                4, 5, 6, 7, 8, 9 ];
    let n = A.length;

    let q
        = [ [ 1, 0, 9 ],
            [ 2, 3, 6 ],
            [ 2, 5, 5 ],
            [ 2, 8, 1 ],
            [ 1, 0, 9 ] ];

    // Create the Binary Indexed Tree
    let BITree = constructBITree(A, n);

    // Solve each query in Q
    for (let i = 0; i < q.length; i++) {
        let id = q[i][0];

        if (id == 1) {
            let L = q[i][1];
            let R = q[i][2];
            document.write("XOR of elements "
                 + "in given range is "
                 + rangeXor(BITree, L, R)
                 + "<br>");
        }
        else {
            let idx = q[i][1];
            let val = q[i][2];
            A[idx] ^= val;

            // Update the values of all
            // ancestors of idx
            updateBIT(BITree, n, idx, val);
        }
    }

</script>

Output: 
XOR of elements in given range is 0
XOR of elements in given range is 2

Time complexity of getXor(): O(log N) 
Time complexity of updateBIT(): O(log N) 
Overall Time complexity: O(M * log N) where M and N are the number of queries and size of the given array respectively.
Auxiliary Space: O(N)


Next Article

Similar Reads