Open In App

Find Array after Q queries where in each query change a[i] to a[i] | x

Improve
Improve
Like Article
Like
Save
Share
Report

Given an array of N elements, initially all a[i] = 0. Q queries need to be performed. Each query contains three integers l, r, and x and you need to change all a[i] to (a[i] | x) for all l ≤ i ≤ r and return the array after executing Q queries.

Examples:

Input: N = 3, Q = 2, U = {{1, 3, 1}, {1, 3, 2}}
Output: a[] = {3, 3, 3}
Explanation: Initially, all elements of the array are 0. After execution of the first query, all elements become 1 and after execution of the second query all elements become 3.

Input: N = 3, Q = 2, U = {{1, 2, 1}, {3, 3, 2}}
Output: a[] = {1, 1, 2}
Explanation: {0, 0, 0] => {1, 1, 0} => {1, 1, 2}

Naive Approach:

  • Initialize the array a of the size N with all elements set to 0.
  • For each query in U:
       – Iterate over the range from the  l to r (inclusive).
       – For each index i, perform the bitwise OR operation between the current value at a[i] and x, and update a[i] with the result.
  • Return the final array a after executing all queries.

Below is the implementation of the above approach:

C++




#include <bits/stdc++.h>
using namespace std;
 
// Function to perform operations on an array based on given
// queries
vector<int> GFG(int N, int Q, vector<vector<int> >& U)
{
    vector<int> a(N, 0);
 
    // Process each query in U
    for (const auto& query : U) {
        // Start index of range
        int l = query[0];
 
        // End index of range
        int r = query[1];
 
        // Value to be ORed
        int x = query[2];
 
        // Perform OR operation on elements within the range
        // [l, r]
        for (int i = l - 1; i < r; ++i) {
            a[i] |= x;
        }
    }
 
    return a;
}
 
int main()
{
    // Number of elements in the array
    int N = 3;
 
    // Number of queries
    int Q = 2;
    vector<vector<int> > U
        = { { 1, 2, 1 },
            { 3, 3, 2 } }; // Queries: [l, r, x]
 
    // Call the function to perform operations on the array
    vector<int> result = GFG(N, Q, U);
 
    // Print the resulting array
    for (const auto& num : result) {
        cout << num << " ";
    }
    cout << endl;
 
    return 0;
}


Java




// Java code for the above approach:
import java.util.ArrayList;
import java.util.List;
 
public class Main {
    // Function to perform operations on an array based on given
    // queries
    public static List<Integer> GFG(int N, int Q, List<List<Integer>> U) {
        List<Integer> a = new ArrayList<>(N);
        for (int i = 0; i < N; i++) {
            a.add(0);
        }
 
        // Process each query in U
        for (List<Integer> query : U) {
            // Start index of range
            int l = query.get(0);
 
            // End index of range
            int r = query.get(1);
 
            // Value to be ORed
            int x = query.get(2);
 
            // Perform OR operation on elements within the range
            // [l, r]
            for (int i = l - 1; i < r; i++) {
                a.set(i, a.get(i) | x);
            }
        }
 
        return a;
    }
 
    public static void main(String[] args) {
        // Number of elements in the array
        int N = 3;
 
        // Number of queries
        int Q = 2;
        List<List<Integer>> U = new ArrayList<>();
        U.add(List.of(1, 2, 1));
        U.add(List.of(3, 3, 2)); // Queries: [l, r, x]
 
        // Call the function to perform operations on the array
        List<Integer> result = GFG(N, Q, U);
 
        // Print the resulting array
        for (int num : result) {
            System.out.print(num + " ");
        }
        System.out.println();
    }
}
 
 
// This code is contributed by Utkarsh Kumar


Python3




# Define a function to perform operations on an array based on given queries
def perform_operations(N, Q, U):
    # Initialize an array of size N with zeros
    a = [0] * N
 
    # Process each query in U
    for query in U:
        # Start index of the range
        l = query[0]
 
        # End index of the range
        r = query[1]
 
        # Value to be ORed
        x = query[2]
 
        # Perform OR operation on elements within the range [l, r]
        for i in range(l - 1, r):
            a[i] |= x
 
    return a
 
if __name__ == "__main__":
    # Number of elements in the array
    N = 3
 
    # Number of queries
    Q = 2
    # Queries: [l, r, x]
    U = [
        [1, 2, 1],
        [3, 3, 2]
    ]
 
    # Call the function to perform operations on the array
    result = perform_operations(N, Q, U)
 
    # Print the resulting array
    for num in result:
        print(num, end=" ")
    print()


C#




using System;
using System.Collections.Generic;
 
class Program
{
    // Function to perform operations on an
    // array based on given queries
    static List<int> Geek(int N, int Q, List<List<int>> U)
    {
        List<int> a = new List<int>(new int[N]);
        // Process each query in U
        foreach (var query in U)
        {
            // Start index of range
            int l = query[0];
            // End index of range
            int r = query[1];
            // Value to be ORed
            int x = query[2];
            // Perform OR operation on elements within
            // the range [l, r]
            for (int i = l - 1; i < r; ++i)
            {
                a[i] |= x;
            }
        }
        return a;
    }
    static void Main(string[] args)
    {
        // Number of elements in the array
        int N = 3;
        // Number of queries
        int Q = 2;
        List<List<int>> U = new List<List<int>>
        {
            new List<int> { 1, 2, 1 },
            new List<int> { 3, 3, 2 },
        }; // Queries: [l, r, x]
        List<int> result = Geek(N, Q, U);
        // Print the resulting array
        foreach (var num in result)
        {
            Console.Write(num + " ");
        }
        Console.WriteLine();
    }
}


Javascript




function performOperations(N, Q, U) {
    const a = new Array(N).fill(0);
 
    // Process each query in U
    for (const query of U) {
        // Start index of range
        const l = query[0];
 
        // End index of range
        const r = query[1];
 
        // Value to be ORed
        const x = query[2];
 
        // Perform OR operation on elements within the range [l, r]
        for (let i = l - 1; i < r; i++) {
            a[i] |= x;
        }
    }
 
    return a;
}
 
// Number of elements in the array
const N = 3;
 
// Number of queries
const Q = 2;
 
// Queries: [l, r, x]
const U = [
    [1, 2, 1],
    [3, 3, 2]
];
 
// Call the function to perform operations on the array
const result = performOperations(N, Q, U);
 
// Print the resulting array
console.log(result.join(' '));


Output

1 1 2 




Time complexity: O(N * Q), where N is the number of elements in the array and Q is the number of queries.
Auxiliary space: O(N) because it uses an additional vector a to store the resulting array of size N.

Efficient Approach:

To solve this problem efficiently, we have to use the concept of difference arrays for each bit.

Below are the steps for the above approach:

  • Create a 2D difference array say, dp[][] of size N*20. For every index, keep an array of size 20 to store the bits and initialize every index as 0.
  • For each query of l, r, and x, increment those indices of the dp[l] array where the bit position of x is set and decrement those indexes of the dp[r+1] array where the bit position of x is set.
  • For each bit, we will run a loop from i=1 to N. And add the value of the previous index to the value of the current index, dp[i][j] += dp[i-1][j].
  • Declare an array, say a[] which will be the answer array.
  • Every inner array of dp[][] array represents a number. That means every index of the inner array represents the bit of a number. So put the numbers in their appropriate positions and return them.

Below is the implementation of the above approach:

C++




// C++ code for the above approach:
#include <bits/stdc++.h>
using namespace std;
 
vector<int> updateQuery(int N, int Q,
                        vector<vector<int> >& U)
{
 
    // Code here
    vector<int> a(N);
    fill(a.begin(), a.end(), 0);
    int dp[N][20];
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < 20; j++)
            dp[i][j] = 0;
    }
    for (int j = 0; j < U.size(); j++) {
        for (int i = 0; i < 20; i++) {
            if (U[j][2] & (1 << i)) {
                dp[U[j][0] - 1][i]++;
                if (U[j][1] < N)
                    dp[U[j][1]][i]--;
            }
        }
    }
    for (int j = 0; j < 20; j++) {
        for (int i = 1; i < N; i++) {
            dp[i][j] += dp[i - 1][j];
        }
    }
    for (int i = 0; i < N; i++) {
        int ans = 0;
        for (int j = 0; j < 20; j++) {
            if (dp[i][j])
                ans += (1 << j);
        }
        a[i] = ans;
    }
    return a;
}
 
// Drivers code
int main()
{
 
    int N = 3, Q = 2;
    vector<vector<int> > u = { { 1, 2, 1 }, { 3, 3, 2 } };
 
    // Function Call
    vector<int> ans = updateQuery(N, Q, u);
    for (auto it : ans)
        cout << it << " ";
    return 0;
}


Java




// Java code for the above approach:
 
import java.util.*;
 
class GFG {
    public static void main(String[] args) {
        int N = 3, Q = 2;
        List<List<Integer>> U = new ArrayList<>();
        U.add(Arrays.asList(1, 2, 1));
        U.add(Arrays.asList(3, 3, 2));
 
        List<Integer> ans = updateQuery(N, Q, U);
        for (int it : ans)
            System.out.print(it + " ");
    }
 
    static List<Integer> updateQuery(int N, int Q, List<List<Integer>> U) {
        List<Integer> a = new ArrayList<>();
        for (int i = 0; i < N; i++)
            a.add(0);
 
        int[][] dp = new int[N][20];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < 20; j++)
                dp[i][j] = 0;
        }
 
        for (int j = 0; j < U.size(); j++) {
            for (int i = 0; i < 20; i++) {
                if ((U.get(j).get(2) & (1 << i)) != 0) {
                    dp[U.get(j).get(0) - 1][i]++;
                    if (U.get(j).get(1) < N)
                        dp[U.get(j).get(1)][i]--;
                }
            }
        }
 
        for (int j = 0; j < 20; j++) {
            for (int i = 1; i < N; i++) {
                dp[i][j] += dp[i - 1][j];
            }
        }
 
        for (int i = 0; i < N; i++) {
            int ansVal = 0;
            for (int j = 0; j < 20; j++) {
                if (dp[i][j] != 0)
                    ansVal += (1 << j);
            }
            a.set(i, ansVal);
        }
        return a;
    }
}


Python3




# Python3 code for the above approach:
 
def updateQuery(N, Q, U):
  # Code here
  a = [0]*N
  dp = [[0]*20 for i in range(N)]
  for j in range(len(U)):
      for i in range(20):
          if (U[j][2] & (1 << i)):
              dp[U[j][0] - 1][i] += 1
              if (U[j][1] < N):
                  dp[U[j][1]][i] -= 1
 
  for j in range(20):
      for i in range(1, N):
          dp[i][j] += dp[i - 1][j]
 
  for i in range(N):
      ans = 0
      for j in range(20):
          if (dp[i][j]):
              ans += (1 << j)
      a[i] = ans
 
  return a
 
# Drivers code
 
N = 3
Q = 2
U = [ [ 1, 2, 1 ], [ 3, 3, 2 ] ]
 
# Function Call
ans = updateQuery(N, Q, U)
for it in ans:
  print(it, end=" ")


C#




// C# code for the above approach:
 
using System;
using System.Collections.Generic;
 
class GFG {
    static List<int> UpdateQuery(int N, int Q,
                                 List<List<int> > U)
    {
        List<int> a = new List<int>(new int[N]);
        int[, ] dp = new int[N, 20];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < 20; j++) {
                dp[i, j] = 0;
            }
        }
        for (int j = 0; j < U.Count; j++) {
            for (int i = 0; i < 20; i++) {
                if ((U[j][2] & (1 << i)) != 0) {
                    dp[U[j][0] - 1, i]++;
                    if (U[j][1] < N) {
                        dp[U[j][1], i]--;
                    }
                }
            }
        }
        for (int j = 0; j < 20; j++) {
            for (int i = 1; i < N; i++) {
                dp[i, j] += dp[i - 1, j];
            }
        }
        for (int i = 0; i < N; i++) {
            int ans = 0;
            for (int j = 0; j < 20; j++) {
                if (dp[i, j] != 0) {
                    ans += (1 << j);
                }
            }
            a[i] = ans;
        }
        return a;
    }
 
    static void Main(string[] args)
    {
        int N = 3, Q = 2;
        List<List<int> > U = new List<List<int> >();
        U.Add(new List<int>{ 1, 2, 1 });
        U.Add(new List<int>{ 3, 3, 2 });
 
        // Function Call
        List<int> ans = UpdateQuery(N, Q, U);
        foreach(var item in ans)
        {
            Console.Write(item + " ");
        }
    }
}


Javascript




// JavaScript code for the above approach:
 
function updateQuery(N, Q, U) {
  let a = new Array(N).fill(0);
  let dp = new Array(N);
  for (let i = 0; i < N; i++) {
    dp[i] = new Array(20).fill(0);
  }
  for (let j = 0; j < U.length; j++) {
    for (let i = 0; i < 20; i++) {
      if (U[j][2] & (1 << i)) {
        dp[U[j][0] - 1][i]++;
        if (U[j][1] < N) {
          dp[U[j][1]][i]--;
        }
      }
    }
  }
  for (let j = 0; j < 20; j++) {
    for (let i = 1; i < N; i++) {
      dp[i][j] += dp[i - 1][j];
    }
  }
  for (let i = 0; i < N; i++) {
    let ans = 0;
    for (let j = 0; j < 20; j++) {
      if (dp[i][j]) {
        ans += 1 << j;
      }
    }
    a[i] = ans;
  }
  return a;
}
 
// Example usage
let N = 3;
let Q = 2;
let U = [[1, 2, 1], [3, 3, 2]];
let ans = updateQuery(N, Q, U);
console.log(ans.join(" ")); // Outputs: 1 1 2


Output

1 1 2 




Time Complexity: O(N)
Auxiliary Space: O(N)



Last Updated : 04 Jan, 2024
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads