Leftover element after performing alternate Bitwise OR and Bitwise XOR operations on adjacent pairs
Last Updated :
09 Aug, 2022
Given an array of N(always a power of 2) elements and Q queries.
Every query consists of two elements, an index, and a value… We need to write a program that assigns value to Aindex and prints the single element which is left after performing the below operations for each query:
- At alternate steps, perform bitwise OR and bitwise XOR operations on the adjacent elements.
- In the first iteration, select, select n/2 pairs moving from left to right, and do a bitwise OR of all the pair values. In the second iteration, select (n/2)/2 leftover pairs and do a bitwise XOR on them. In the third iteration, select, select ((n/2)/2)/2 leftover pairs moving from left to right, and do a bitwise OR of all the pair values.
- Continue the above steps till we are left with a single element.
Examples:
Input : n = 4 m = 2
arr = [1, 4, 5, 6]
Queries-
1st: index=0 value=2
2nd: index=3 value=5
Output : 1
3
Explanation:
1st query:
Assigning 2 to index 0, the sequence is now
[2, 4, 5, 6].
1st iteration: There are 4/2=2 pairs (2, 4) and (5, 6)
2 OR 4 gives 6, and 5 OR 6 gives us 7. So the
sequence is now [6, 7].
2nd iteration: There is 1 pair left now (6, 7)
6^7=1.
Hence the last element left is 1 which is the
answer to our first query.
2nd Query:
Assigning 5 to index 3, the sequence is now
[2, 4, 5, 5].
1st iteration: There are 4/2=2 pairs (2, 4) and (5, 5)
2 OR 4 gives 6, and 5 OR 5 gives us 5. So the
sequence is now [6, 5].
2nd iteration: There is 1 pair left now (6, 5)
6^5=3.
Hence the last element left is 3 which is the
answer to our second query.
Naive Approach: The naive approach is to perform every step till we are leftover with one element. Using a 2-D vector, we will store the resultant elements left after every step. V[steps-1][0..size] gives the number of elements at the previous step. If the step number is odd, we perform a bitwise OR operation, else a bitwise XOR operation is done. Repeat the steps till we have a leftover with one element. The last element left will be our answer.
Below is the implementation of the naive approach:
C++
#include <bits/stdc++.h>
using namespace std;
#define N 1000
int lastElement( int a[], int n)
{
int steps = 1;
vector< int >v[N];
if (n==1) return a[0];
for ( int i = 0 ; i < n ; i += 2)
v[steps].push_back(a[i] | a[i+1]);
while (v[steps].size()>1)
{
steps += 1;
for ( int i = 0 ; i < v[steps-1].size(); i+=2)
{
if (steps&1)
v[steps].push_back(v[steps-1][i] | v[steps-1][i+1]);
else
v[steps].push_back(v[steps-1][i] ^ v[steps-1][i+1]);
}
}
return v[steps][0];
}
int main()
{
int a[] = {1, 4, 5, 6};
int n = sizeof (a)/ sizeof (a[0]);
int index = 0;
int value = 2;
a[0] = 2;
cout << lastElement(a,n) << endl;
index = 3;
value = 5;
a[index] = value;
cout << lastElement(a,n) << endl;
return 0;
}
|
Java
import java.util.*;
class GFG
{
static int N = 1000 ;
static int lastElement( int a[], int n)
{
int steps = 1 ;
Vector<Integer> []v = new Vector[N];
for ( int i = 0 ; i < N; i++)
v[i] = new Vector<Integer>();
if (n == 1 ) return a[ 0 ];
for ( int i = 0 ; i < n ; i += 2 )
v[steps].add(a[i] | a[i + 1 ]);
while (v[steps].size() > 1 )
{
steps += 1 ;
for ( int i = 0 ; i < v[steps - 1 ].size(); i += 2 )
{
if (steps % 2 == 1 )
v[steps].add(v[steps - 1 ].get(i) |
v[steps - 1 ].get(i + 1 ));
else
v[steps].add(v[steps - 1 ].get(i) ^
v[steps - 1 ].get(i + 1 ));
}
}
return v[steps].get( 0 );
}
public static void main(String[] args)
{
int a[] = { 1 , 4 , 5 , 6 };
int n = a.length;
int index = 0 ;
int value = 2 ;
a[ 0 ] = 2 ;
System.out.println(lastElement(a, n));
index = 3 ;
value = 5 ;
a[index] = value;
System.out.println(lastElement(a, n));
}
}
|
Python3
N = 1000
def lastElement(a, n):
steps = 1
v = [[] for i in range (n)]
if n = = 1 : return a[ 0 ]
for i in range ( 0 , n, 2 ):
v[steps].append(a[i] | a[i + 1 ])
while len (v[steps]) > 1 :
steps + = 1
for i in range ( 0 , len (v[steps - 1 ]), 2 ):
if steps & 1 :
v[steps].append(v[steps - 1 ][i] | v[steps - 1 ][i + 1 ])
else :
v[steps].append(v[steps - 1 ][i] ^ v[steps - 1 ][i + 1 ])
return v[steps][ 0 ]
if __name__ = = "__main__" :
a = [ 1 , 4 , 5 , 6 ]
n = len (a)
index, value, a[ 0 ] = 0 , 2 , 2
print (lastElement(a,n))
index, value = 3 , 5
value = 5
a[index] = value
print (lastElement(a,n))
|
C#
using System;
using System.Collections.Generic;
class GFG
{
static int N = 1000;
static int lastElement( int []a, int n)
{
int steps = 1;
List< int > []v = new List< int >[N];
for ( int i = 0; i < N; i++)
v[i] = new List< int >();
if (n == 1)
return a[0];
for ( int i = 0 ; i < n ; i += 2)
v[steps].Add(a[i] | a[i + 1]);
while (v[steps].Count > 1)
{
steps += 1;
for ( int i = 0; i < v[steps - 1].Count; i += 2)
{
if (steps % 2 == 1)
v[steps].Add(v[steps - 1][i] |
v[steps - 1][i + 1]);
else
v[steps].Add(v[steps - 1][i] ^
v[steps - 1][i + 1]);
}
}
return v[steps][0];
}
public static void Main(String[] args)
{
int []a = {1, 4, 5, 6};
int n = a.Length;
int index = 0;
int value = 2;
a[0] = 2;
Console.WriteLine(lastElement(a, n));
index = 3;
value = 5;
a[index] = value;
Console.WriteLine(lastElement(a, n));
}
}
|
Javascript
<script>
var N = 1000
function lastElement(a,n)
{
var steps = 1;
var v = Array.from(Array(N), ()=>Array(0));
if (n==1)
return a[0];
for ( var i = 0 ; i < n ; i += 2)
v[steps].push(a[i] | a[i+1]);
while (v[steps].length>1)
{
steps += 1;
for ( var i = 0 ; i < v[steps-1].length; i+=2)
{
if (steps&1)
v[steps].push(v[steps-1][i] | v[steps-1][i+1]);
else
v[steps].push(v[steps-1][i] ^ v[steps-1][i+1]);
}
}
return v[steps][0];
}
var a = [1, 4, 5, 6];
var n = a.length;
var index = 0;
var value = 2;
a[0] = 2;
document.write( lastElement(a,n) + "<br>" );
index = 3;
value = 5;
a[index] = value;
document.write( lastElement(a,n));
</script>
|
Time Complexity: O(N * 2N )
Space Complexity: O(N ^ 2)
Efficient Approach: The efficient approach is to use a Segment tree. Below is the complete segment tree approach used to solve the problem.
Building the tree
The leaves of the segment tree will store the array of values and their parents will store the OR of the leaves. Moving upward in the tree, with every alternate step, the parent stores either bitwise XOR or bitwise OR between the left and right child. At every odd-numbered iteration, we perform the bitwise OR of the pairs, and similarly, we perform the bitwise XOR of pairs at every even-numbered operation. So the odd-numbered parent will store the bitwise OR of the left and right child. Similarly, the even-numbered parent stores the bitwise XOR of the left and right child. level[] is an array that stores levels of every parent starting from 1, to determine if the pair(right child and left child) below it performs an OR operation or an XOR operation. The root of the tree will be our answer to the given sequence after every update operation.
The image above explains the construction of the tree. If the sequence was [1, 2, 3, 4, 5, 6, 7, 8], then after 3 iterations, we will be left over with 12 which is our answer and is stored at the root.
Answering Query:
There is no need to rebuild the complete tree to perform an update operation. To do an update, we should find a path from the root to the corresponding leaf and recalculate the values only for the parents that are lying on the found path.
Level of parent:
Using DP on trees, we can easily store the level of every parent. Initialize the leaf nodes level to 0, and keep adding as we move up to every parent.
The recurrence relation for calculating the level of parent is:
level[parent] = level[child] + 1
Here, a child is 2*pos + 1 or 2*pos + 2
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
#define N 1000
int tree[N];
int level[N];
void constructTree( int low, int high, int pos, int a[])
{
if (low == high)
{
level[pos] = 0;
tree[pos] = a[high];
return ;
}
int mid = (low + high) / 2;
constructTree(low, mid, 2 * pos + 1, a);
constructTree(mid + 1, high, 2 * pos + 2, a);
level[pos] = level[2 * pos + 1] + 1;
if (level[pos] & 1)
tree[pos] = tree[2 * pos + 1] | tree[2 * pos + 2];
else
tree[pos] = tree[2 * pos + 1] ^ tree[2 * pos + 2];
}
void update( int low, int high, int pos, int index, int a[])
{
if (low == high and low == index)
{
tree[pos] = a[low];
return ;
}
if (index < low || index > high)
return ;
if (low != high)
{
int mid = (low + high) / 2;
update(low, mid, 2 * pos + 1, index, a);
update(mid + 1, high, 2 * pos + 2, index, a);
if (level[pos] & 1)
tree[pos] = tree[2 * pos + 1] | tree[2 * pos + 2];
else
tree[pos] = tree[2 * pos + 1] ^ tree[2 * pos + 2];
}
}
void updateValue( int index, int value, int a[], int n)
{
a[index] = value;
update(0, n - 1, 0, index, a);
}
int main()
{
int a[] = { 1, 4, 5, 6 };
int n = sizeof (a) / sizeof (a[0]);
constructTree(0, n - 1, 0, a);
int index = 0;
int value = 2;
updateValue(index, value, a, n);
cout << tree[0] << endl;
index = 3;
value = 5;
updateValue(index, value, a, n);
cout << tree[0] << endl;
return 0;
}
|
Java
import java .io.*;
public class GFG {
static int N = 1000 ;
static int []tree = new int [N];
static int []level = new int [N];
static void constructTree( int low, int high,
int pos, int []a)
{
if (low == high)
{
level[pos] = 0 ;
tree[pos] = a[high];
return ;
}
int mid = (low + high) / 2 ;
constructTree(low, mid, 2 * pos + 1 , a);
constructTree(mid + 1 , high,
2 * pos + 2 , a);
level[pos] = level[ 2 * pos + 1 ] + 1 ;
if ((level[pos] & 1 ) > 0 )
tree[pos] = tree[ 2 * pos + 1 ] |
tree[ 2 * pos + 2 ];
else
tree[pos] = tree[ 2 * pos + 1 ] ^
tree[ 2 * pos + 2 ];
}
static void update( int low, int high, int pos,
int index, int []a)
{
if (low == high && low == index)
{
tree[pos] = a[low];
return ;
}
if (index < low || index > high)
return ;
if (low != high)
{
int mid = (low + high) / 2 ;
update(low, mid, 2 * pos + 1 , index, a);
update(mid + 1 , high, 2 * pos + 2 ,
index, a);
if ((level[pos] & 1 ) > 0 )
tree[pos] = tree[ 2 * pos + 1 ] |
tree[ 2 * pos + 2 ];
else
tree[pos] = tree[ 2 * pos + 1 ] ^
tree[ 2 * pos + 2 ];
}
}
static void updateValue( int index, int value,
int []a, int n)
{
a[index] = value;
update( 0 , n - 1 , 0 , index, a);
}
static public void main (String[] args)
{
int []a = { 1 , 4 , 5 , 6 };
int n = a.length;;
constructTree( 0 , n - 1 , 0 , a);
int index = 0 ;
int value = 2 ;
updateValue(index, value, a, n);
System.out.println(tree[ 0 ]);
index = 3 ;
value = 5 ;
updateValue(index, value, a, n);
System.out.println(tree[ 0 ]);
}
}
|
Python3
N = 1000
tree = [ None ] * N
level = [ None ] * N
def constructTree(low, high, pos, a):
if low = = high:
level[pos], tree[pos] = 0 , a[high]
return
mid = (low + high) / / 2
constructTree(low, mid, 2 * pos + 1 , a)
constructTree(mid + 1 , high, 2 * pos + 2 , a)
level[pos] = level[ 2 * pos + 1 ] + 1
if level[pos] & 1 :
tree[pos] = tree[ 2 * pos + 1 ] | tree[ 2 * pos + 2 ]
else :
tree[pos] = tree[ 2 * pos + 1 ] ^ tree[ 2 * pos + 2 ]
def update(low, high, pos, index, a):
if low = = high and low = = index:
tree[pos] = a[low]
return
if index < low or index > high:
return
if low ! = high:
mid = (low + high) / / 2
update(low, mid, 2 * pos + 1 , index, a)
update(mid + 1 , high, 2 * pos + 2 , index, a)
if level[pos] & 1 :
tree[pos] = tree[ 2 * pos + 1 ] | tree[ 2 * pos + 2 ]
else :
tree[pos] = tree[ 2 * pos + 1 ] ^ tree[ 2 * pos + 2 ]
def updateValue(index, value, a, n):
a[index] = value
update( 0 , n - 1 , 0 , index, a)
if __name__ = = "__main__" :
a = [ 1 , 4 , 5 , 6 ]
n = len (a)
constructTree( 0 , n - 1 , 0 , a)
index, value = 0 , 2
updateValue(index, value, a, n)
print (tree[ 0 ])
index, value = 3 , 5
updateValue(index, value, a, n)
print (tree[ 0 ])
|
C#
using System;
public class GFG {
static int N = 1000;
static int []tree = new int [N];
static int []level = new int [N];
static void constructTree( int low, int high,
int pos, int []a)
{
if (low == high)
{
level[pos] = 0;
tree[pos] = a[high];
return ;
}
int mid = (low + high) / 2;
constructTree(low, mid, 2 * pos + 1, a);
constructTree(mid + 1, high,
2 * pos + 2, a);
level[pos] = level[2 * pos + 1] + 1;
if ((level[pos] & 1) > 0)
tree[pos] = tree[2 * pos + 1] |
tree[2 * pos + 2];
else
tree[pos] = tree[2 * pos + 1] ^
tree[2 * pos + 2];
}
static void update( int low, int high,
int pos, int index, int []a)
{
if (low == high && low == index)
{
tree[pos] = a[low];
return ;
}
if (index < low || index > high)
return ;
if (low != high)
{
int mid = (low + high) / 2;
update(low, mid, 2 * pos + 1,
index, a);
update(mid + 1, high, 2 * pos + 2,
index, a);
if ((level[pos] & 1) > 0)
tree[pos] = tree[2 * pos + 1] |
tree[2 * pos + 2];
else
tree[pos] = tree[2 * pos + 1]
^ tree[2 * pos + 2];
}
}
static void updateValue( int index, int value,
int []a, int n)
{
a[index] = value;
update(0, n - 1, 0, index, a);
}
static public void Main ()
{
int []a = { 1, 4, 5, 6 };
int n = a.Length;;
constructTree(0, n - 1, 0, a);
int index = 0;
int value = 2;
updateValue(index, value, a, n);
Console.WriteLine(tree[0]);
index = 3;
value = 5;
updateValue(index, value, a, n);
Console.WriteLine(tree[0]);
}
}
|
Javascript
<script>
let N = 1000;
let tree = new Array(N);
tree.fill(0);
let level = new Array(N);
level.fill(0);
function constructTree(low, high, pos, a)
{
if (low == high)
{
level[pos] = 0;
tree[pos] = a[high];
return ;
}
let mid = parseInt((low + high) / 2, 10);
constructTree(low, mid, 2 * pos + 1, a);
constructTree(mid + 1, high, 2 * pos + 2, a);
level[pos] = level[2 * pos + 1] + 1;
if ((level[pos] & 1) > 0)
tree[pos] = tree[2 * pos + 1] |
tree[2 * pos + 2];
else
tree[pos] = tree[2 * pos + 1] ^
tree[2 * pos + 2];
}
function update(low, high, pos, index, a)
{
if (low == high && low == index)
{
tree[pos] = a[low];
return ;
}
if (index < low || index > high)
return ;
if (low != high)
{
let mid = parseInt((low + high) / 2, 10);
update(low, mid, 2 * pos + 1,
index, a);
update(mid + 1, high, 2 * pos + 2,
index, a);
if ((level[pos] & 1) > 0)
tree[pos] = tree[2 * pos + 1] |
tree[2 * pos + 2];
else
tree[pos] = tree[2 * pos + 1]
^ tree[2 * pos + 2];
}
}
function updateValue(index, value, a, n)
{
a[index] = value;
update(0, n - 1, 0, index, a);
}
let a = [ 1, 4, 5, 6 ];
let n = a.length;;
constructTree(0, n - 1, 0, a);
let index = 0;
let value = 2;
updateValue(index, value, a, n);
document.write(tree[0] + "</br>" );
index = 3;
value = 5;
updateValue(index, value, a, n);
document.write(tree[0]);
</script>
|
Time Complexity:
- Tree construction: O(N)
- Answering Query: O(log2N)
Space Complexity: O(N)
Share your thoughts in the comments
Please Login to comment...