Find the final Array by updating given Ranges
Given an array arr[] consisting of N integers and an array Q[][3] consisting of M queries of the form [L, R, U], the task for each query is to xor every array element over the range [L, R] with U, After processing each query print the final array.
Examples:
Input: arr[] = {0, 0, 0, 0, 0, 0, 0}, Q[][] = {{2, 4, 1}, {0, 4, 2}, {1, 5, 3}}
Output: Initial Array : 0 0 0 0 0 0 0
Final Array : 2 1 0 0 0 3 0
Explanation: Query 1: For query {2, 4, 1} xor every index from 2 to 4 with 1 so it becomes {0, 0, 1, 1, 1, 0, 0}
Query 2: For query {0, 4, 2} xor every index from 0 to 4 with 2 so it becomes {2, 2, 1 ^ 2, 1 ^ 2, 1 ^ 2, 0, 0} which is {2, 2, 3, 3, 3, 0, 0}
Query 3: For query {1, 5, 3} xor every index from 1 to 5 with 3 so it becomes {2, 2 ^ 3, 1 ^ 2 ^ 3, 1 ^ 2 ^ 3, 1 ^ 2 ^ 3, 3, 0} which is {2, 1, 0, 0, 0, 3, 0}Input: arr[] = {1, 2, 4, 3, 9}, Q[][] = {{0, 3, 15}, {0, 4, 15}}
Output: Initial Array : 1 2 4 3 9
Final Array : 14 13 11 12 6
Naive Approach: The basic way to solve the problem is as follows:
Iterate from L to R and xor U to all elements from arr[L] to arr[R] for each query.
Time Complexity: O(N * M) where M is the number of queries.
Auxiliary Space: O(1)
Efficient Approach: The above approach can be optimized based on the following idea:
We can utilise prefix xor (similar to prefix sum) efficiently to be able to perform following queries in constant time. Idea is if we take xor of prefix[L] with U and xor of prefix[R + 1] with U again after doing prefix XOR we can observe that L to R gets updated with xor with U. But when we try to take xor at R + 1 XOR that was carrying itself forward from L in prefix xor gets deleted at R + 1 (since x ^ x == 0).
For Example: {0, 0, 0, 0, 0} and L = 1, R = 3 and U = 10
Updating array at L and R + 1 with U: {0, 10, 0, 0, 10}
- STEP 1: {0, 10, 0, 0, 10}
- STEP 2: {0, 10, 10, 0, 10}
- STEP 3: {0, 10, 10, 10, 10}
- STEP 4: {0, 10, 10, 10, 10 ^ 10} that is {0, 10, 10, 10, 0}
This can be observed that 10 was carrying itself forward but at R + 1 it gets deleted and range from L to R gets updated with xor U. This can be used for all queries.
Follow the steps below to solve the problem:
- The pre-computation array prefix[] is defined
- Traversing for each M query and taking xor of prefix[L] with U and prefix[R + 1] with U.
- Taking prefix xor for every U for M queries carries itself forward from L to R and ends at R + 1.
- Taking xor of respective indexes of the initial array with prefix array and then printing it.
Below is the implementation of the above approach:
C++
// C++ code to implement the approach #include <bits/stdc++.h> using namespace std; // Function to process given range xor // update queries then printing the // final array void printFinalArray(int arr[], int N, int Q[][3], int M) { // printing initial array cout << "Initial Array: "; for (int i = 0; i < N; i++) { cout << arr[i] << " "; } cout << endl; // Precomputation array // used for range update int prefix[N + 1] = { 0 }; // Traverse the given queries for (int i = 0; i < M; i++) { // Stores range L, R and U for // each query int L = Q[i][0], R = Q[i][1], U = Q[i][2]; for (int i = L; i <= R; i++) { // Updating L and R + 1 with U prefix[L] = prefix[L] ^ U; prefix[R + 1] = prefix[R + 1] ^ U; } } // Taking prefix xor // so that every U for M queries // carries itself forward from L // to R and end at R + 1 for (int i = 1; i < N; i++) { prefix[i] = prefix[i] ^ prefix[i - 1]; } // finally printing Final array cout << "Final Array: "; for (int i = 0; i < N; i++) { // Taking xor with initial array of // prefix array so range updates // can be made in initial array arr[i] = arr[i] ^ prefix[i]; cout << arr[i] << " "; } } // Driver Code int main() { int arr[] = { 0, 0, 0, 0, 0, 0, 0 }; int Q[][3] = { { 2, 4, 1 }, { 0, 4, 2 }, { 1, 5, 3 } }; int N = sizeof(arr) / sizeof(arr[0]); int M = sizeof(Q) / sizeof(Q[0]); // Function Call printFinalArray(arr, N, Q, M); return 0; }
Java
// Java code to implement the approach import java.io.*; import java.util.*; class GFG { // Function to process given range xor // update queries then printing the // final array static void printFinalArray(int[] arr, int N, int[][] Q, int M) { // Printing initial array System.out.print("Initial Array: "); for (int i = 0; i < N; i++) { System.out.print(arr[i] + " "); } System.out.println(); // Precomputation array // used for range update int[] prefix = new int[N + 1]; Arrays.fill(prefix, 0); // Traverse the given queries for (int i = 0; i < M; i++) { // Stores range L, R and U for // each query int L = Q[i][0], R = Q[i][1], U = Q[i][2]; for (int j = L; j <= R; j++) { // Updating L and R + 1 with U prefix[L] = prefix[L] ^ U; prefix[R + 1] = prefix[R + 1] ^ U; } } // Taking prefix xor // so that every U for M queries // carries itself forward from L // to R and end at R + 1 for (int i = 1; i < N; i++) { prefix[i] = prefix[i] ^ prefix[i - 1]; } // finally printing Final array System.out.print("Final Array: "); for (int i = 0; i < N; i++) { // Taking xor with initial array of // prefix array so range updates // can be made in initial array arr[i] = arr[i] ^ prefix[i]; System.out.print(arr[i] + " "); } } public static void main(String[] args) { int[] arr = { 0, 0, 0, 0, 0, 0, 0 }; int[][] Q = { { 2, 4, 1 }, { 0, 4, 2 }, { 1, 5, 3 } }; int N = arr.length; int M = Q.length; // Function call printFinalArray(arr, N, Q, M); } } // This code is contributed by lokesh.
Python3
# Python code to implement the approach # Function to process given range xor # update queries then printing the # final array def printFinalArray(arr,N,Q,M): # printing initial array print("Initial Array: ") for i in range(N): print(arr[i],end=" ") print() # Precomputation array # used for range update prefix=[0]*(N+1) # Traverse the given queries for i in range(M): # Stores range L, R and U for # each query L=Q[i][0] R=Q[i][1] U=Q[i][2] for i in range(L,R+1): # Updating L and R + 1 with U prefix[L]=prefix[L]^U prefix[R+1]=prefix[R+1]^U # Taking prefix xor # so that every U for M queries # carries itself forward from L # to R and end at R + 1 for i in range(1,N): prefix[i]=prefix[i]^prefix[i-1] # finally printing Final array print("Final Array: ") for i in range(N): # Taking xor with initial array of # prefix array so range updates # can be made in initial array arr[i]=arr[i]^prefix[i] print(arr[i],end=" ") # Driver Code arr=[0, 0, 0, 0, 0, 0, 0] Q=[[2,4,1],[0,4,2],[1,5,3]] N=len(arr) M=len(Q) # Function Call printFinalArray(arr,N,Q,M) # This code is contributed by Pushpesh Raj.
C#
// C# code to implement the approach using System; using System.Collections; using System.Collections.Generic; public class GFG { // Function to process given range xor // update queries then printing the // final array static void printFinalArray(int[] arr, int N, int[, ] Q, int M) { // Printing initial array Console.Write("Initial Array: "); for (int i = 0; i < N; i++) { Console.Write(arr[i] + " "); } Console.WriteLine(); // Precomputation array // used for range update int[] prefix = new int[N + 1]; Array.Fill(prefix, 0); // Traverse the given queries for (int i = 0; i < M; i++) { // Stores range L, R and U for // each query int L = Q[i, 0], R = Q[i, 1], U = Q[i, 2]; for (int j = L; j <= R; j++) { // Updating L and R + 1 with U prefix[L] = prefix[L] ^ U; prefix[R + 1] = prefix[R + 1] ^ U; } } // Taking prefix xor // so that every U for M queries // carries itself forward from L // to R and end at R + 1 for (int i = 1; i < N; i++) { prefix[i] = prefix[i] ^ prefix[i - 1]; } // finally printing Final array Console.Write("Final Array: "); for (int i = 0; i < N; i++) { // Taking xor with initial array of // prefix array so range updates // can be made in initial array arr[i] = arr[i] ^ prefix[i]; Console.Write(arr[i] + " "); } } static public void Main() { // Code int[] arr = { 0, 0, 0, 0, 0, 0, 0 }; int[, ] Q = { { 2, 4, 1 }, { 0, 4, 2 }, { 1, 5, 3 } }; int N = arr.Length; int M = Q.GetLength(0); // Function call printFinalArray(arr, N, Q, M); } } // This code is contributed by lokeshmvs21.
Javascript
// JavaScript code to implement the approach // Function to process given range xor // update queries then printing the // final array const printFinalArray = (arr, N, Q, M) => { // printing initial array document.write("Initial Array: "); for (let i = 0; i < N; i++) { console.log(`${arr[i]} `); } console.log("<br/>"); // Precomputation array // used for range update let prefix = new Array(N + 1).fill(0); // Traverse the given queries for (let i = 0; i < M; i++) { // Stores range L, R and U for // each query let L = Q[i][0], R = Q[i][1], U = Q[i][2]; for (let i = L; i <= R; i++) { // Updating L and R + 1 with U prefix[L] = prefix[L] ^ U; prefix[R + 1] = prefix[R + 1] ^ U; } } // Taking prefix xor // so that every U for M queries // carries itself forward from L // to R and end at R + 1 for (let i = 1; i < N; i++) { prefix[i] = prefix[i] ^ prefix[i - 1]; } // finally printing Final array console.log("Final Array: "); for (let i = 0; i < N; i++) { // Taking xor with initial array of // prefix array so range updates // can be made in initial array arr[i] = arr[i] ^ prefix[i]; console.log(`${arr[i]} `); } } // Driver Code let arr = [0, 0, 0, 0, 0, 0, 0]; let Q = [[2, 4, 1], [0, 4, 2], [1, 5, 3]]; let N = arr.length; let M = Q.length; // Function Call printFinalArray(arr, N, Q, M); // This code is contributed by rakeshsahni
Initial Array : 0 0 0 0 0 0 0 Final Array : 2 1 0 0 0 3 0
Time Complexity: O(N + M)
Auxiliary Space: O(N)
Please Login to comment...