Skip to content
Related Articles

Related Articles

Queries to replace subarrays by equal length arrays with at most P replacements allowed for any array element
  • Difficulty Level : Easy
  • Last Updated : 15 Dec, 2020

Given an array, arr[] of size N, an integer P and a 2D array Q[][] consisting of queries of the following type:

  • 1 L R B[R – L + 1]: The task for this query is to replace the subarray {arr[L], … arr[R] with the array B[] b given that any array element can be replaced at most P times.
  • 2 X: The task for this query is to print arr[X].

Examples:

Input: arr[] = {3, 10, 4, 2, 8, 7}, P = 1, Q[][] = {{1, 0, 3, 3, 2, 1, 11}, {2, 3}, {1, 2, 3, 5, 7}, {2, 2} }
Output: 11 1
Explanation:
Query 1: Replacing the subarray {arr[0], …, arr[3]} with the array {3, 2, 1, 11} modifies arr[] to {3, 2, 1, 11, 8, 7}
Query 2: Print arr[3].
Query 3: Since P = 1, therefore the subarray {arr[2], …, arr[3]} can’t be replaced more than once.
Query 4: Print arr[2].

Input: arr[] = {1, 2, 3, 4, 5}, P = 2, Q[][] = {{2, 0}, {1, 1, 3, 6, 7, 8}, {1, 3, 4, 10, 12}, {2, 4}}
Output: 1 12

Approach: The problem can be solved using the Union-Find algorithm. The idea is to traverse the array Q[][] and check if Q[0] is equal to 1 or not. If found to be true, then replace the subarray with the new array and whenever any array element has been replaced P times, then create a new subset using the union-find. Follow the steps below to solve the problem:



  • Initialize an array, say visited[], where visited[i] check index i is present in any disjoint subset or not.
  • Initialize an array, say count[], where count[i] stores how many times arr[i] has been replaced.
  • Initialize an array, say last[], to store the largest element of each disjoint subset.
  • Initialize an array, say parent[], to store the smallest element of each disjoint subset.
  • Traverse the Q[][] array and for each query check if Q[i][0] == 1 or not. If found to be true then perform the following operations: 
    • Iterate over the range [ Q[i][1], Q[i][2] ] using variable low and check if visited[low] is true or not. If found to be true then find the parent of that subset where low present, find the largest element present in the subset.
    • Otherwise, check if count[low] is less than P or not. If found to be true then replace the value of arr[low] with the corresponding value.
    • Otherwise, check if count[low] is equal to P or not. If found to be true then create a new disjoint subset of the current index.
  • Otherwise, print arr[Q[i][1]]].

Below is the implementation of the above approach:

Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java program to implement
// the above approach
 
import java.io.*;
import java.util.*;
 
class GFG {
 
    // visited[i]: Check index i is present
    // in any disjoint subset or not.
    static boolean[] visited;
 
    // Store the smallest element
    // of each disjoint subset
    static int[] parent;
 
    // count[i]: Stores the count
    // of replacements of arr[i]
    static int[] last;
 
    // Store the largest element
    // of each disjoint subset
    static int[] count;
 
    // Function to process all the given Queries
    static void processQueries(int[] arr, int P,
                               List<List<Integer> > Q)
    {
        // Traverse the queries[][] array
        for (int i = 0; i < Q.size(); i++) {
 
            // Stores the current query
            List<Integer> query = Q.get(i);
 
            // If query of type is 1
            if (query.get(0) == 1) {
 
                // Perform the query of type 1
                processTypeOneQuery(query, arr, P);
            }
 
            // If query of type is 2
            else {
 
                // Stores 2nd element of
                // current query
                int index = query.get(1);
 
                // Print arr[index]
                System.out.println(arr[index]);
            }
        }
    }
 
    // Function to perform the query of type 1
    static void processTypeOneQuery(
        List<Integer> query, int[] arr, int P)
    {
        // Stores the value of L
        int low = query.get(1);
 
        // Stores the value of R
        int high = query.get(2);
 
        // Stores leftmost index of the
        // subarray for which a new
        // subset can be generated
        int left = -1;
 
        // Stores index of
        // the query[] array
        int j = 3;
 
        // Iterate over the
        // range [low, high]
        while (low <= high) {
 
            // If low is present in
            // any of the subset
            if (visited[low]) {
 
                // If no subset created for
                // the subarray arr[left...low - 1]
                if (left != -1) {
 
                    // Create a new subset
                    newUnion(left, low - 1,
                             arr.length);
 
                    // Update left
                    left = -1;
                }
 
                // Stores next index to be
                // processed
                int jump = findJumpLength(low);
 
                // Update low
                low += jump;
 
                // Update j
                j += jump;
            }
 
            // If arr[low] has been
            // already replaced P times
            else if (count[low] == P) {
 
                // If already subset
                // created for left
                if (left == -1) {
 
                    // Update left
                    left = low;
                }
 
                // Mark low as an element
                // of any subset
                visited[low] = true;
 
                // Update low
                low++;
 
                // Update j
                j++;
            }
 
            // If arr[low] has been replaced
            // less than P times
            else {
 
                // If no subset created for
                // the subarray arr[left...low - 1]
                if (left != -1) {
 
                    // Create a new subset
                    newUnion(left, low - 1, arr.length);
 
                    // Update left
                    left = -1;
                }
 
                // Replace arr[low] with
                // the corresponding value
                arr[low] = query.get(j);
 
                // Update count[low]
                count[low]++;
 
                // Update low
                low++;
 
                // Update j
                j++;
            }
        }
 
        // If no subset has been created for
        // the subarray arr[left...low - 1]
        if (left != -1) {
 
            // Create a new subset
            newUnion(left, high, arr.length);
        }
    }
 
    // Function to find the next index
    // to be processed after visiting low
    static int findJumpLength(int low)
    {
 
        // Stores smallest index of
        // the subset where low present
        int p = findParent(low);
 
        // Stores next index
        // to be processed
        int nextIndex = last[p] + 1;
 
        // Stores difference between
        // low and nextIndex
        int jump = (nextIndex - low);
 
        // Return jump
        return jump;
    }
 
    // Function to create a new subset
    static void newUnion(int low, int high,
                         int N)
    {
 
        // Iterate over
        // the range [low + 1, high]
        for (int i = low + 1; i <= high;
             i++) {
 
            // Perform union operation
            // on low
            union(low, i);
        }
 
        // If just smaller element of low
        // is present in any of the subset
        if (low > 0 && visited[low - 1]) {
 
            // Perform union on (low - 1)
            union(low - 1, low);
        }
 
        // If just greater element of high
        // is present in any of the subset
        if (high < N - 1 && visited[high + 1]) {
 
            // Perform union on high
            union(high, high + 1);
        }
    }
 
    // Function to find the smallest
    // element of the subset
    static int findParent(int u)
    {
 
        // Base Case
        if (parent[u] == u)
            return u;
 
        // Stores smallest element
        // of parent[u
        return parent[u]
            = findParent(parent[u]);
    }
 
    // Function to perform union operation
    static void union(int u, int v)
    {
        // Stores smallest element
        // of subset containing u
        int p1 = findParent(u);
 
        // Stores smallest element
        // of subset containing u
        int p2 = findParent(v);
 
        // Update parent[p2]
        parent[p2] = p1;
 
        // Update last[p1]
        last[p1] = last[p2];
    }
 
    // Function to find all the queries
    static List<List<Integer> > getQueries()
    {
 
        // Stores all the queries
        List<List<Integer> > Q
            = new ArrayList<List<Integer> >();
 
        // Initialize all queries
        Integer[] query1 = { 1, 0, 3, 3, 2,
                             1, 11 };
        Integer[] query2 = { 2, 3 };
        Integer[] query3 = { 1, 2, 3, 5, 7 };
        Integer[] query4 = { 2, 2 };
 
        // Insert all queries
        Q.add(Arrays.asList(query1));
        Q.add(Arrays.asList(query2));
        Q.add(Arrays.asList(query3));
        Q.add(Arrays.asList(query4));
 
        // Return all queries
        return Q;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        int[] arr = { 3, 10, 4, 2, 8, 7 };
        int N = arr.length;
        int P = 1;
 
        parent = new int[N];
        last = new int[N];
        count = new int[N];
        visited = new boolean[N];
 
        // Initialize parent[] and
        // last[] array
        for (int i = 0; i < parent.length;
             i++) {
 
            // Update parent[i]
            parent[i] = i;
 
            // Update last[i]
            last[i] = i;
        }
 
        List<List<Integer> > Q = getQueries();
        processQueries(arr, P, Q);
    }
}

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# program to implement
// the above approach
using System;
using System.Collections.Generic;
 
public class GFG {
 
    // visited[i]: Check index i is present
    // in any disjoint subset or not.
    static bool[] visited;
 
    // Store the smallest element
    // of each disjoint subset
    static int[] parent;
 
    // count[i]: Stores the count
    // of replacements of arr[i]
    static int[] last;
 
    // Store the largest element
    // of each disjoint subset
    static int[] count;
 
    // Function to process all the given Queries
    static void processQueries(int[] arr, int P,
                               List<List<int> > Q)
    {
       
        // Traverse the [,]queries array
        for (int i = 0; i < Q.Count; i++) {
 
            // Stores the current query
            List<int> query = Q[i];
 
            // If query of type is 1
            if (query[0] == 1) {
 
                // Perform the query of type 1
                processTypeOneQuery(query, arr, P);
            }
 
            // If query of type is 2
            else {
 
                // Stores 2nd element of
                // current query
                int index = query[1];
 
                // Print arr[index]
                Console.WriteLine(arr[index]);
            }
        }
    }
 
    // Function to perform the query of type 1
    static void processTypeOneQuery(
        List<int> query, int[] arr, int P)
    {
        // Stores the value of L
        int low = query[1];
 
        // Stores the value of R
        int high = query[2];
 
        // Stores leftmost index of the
        // subarray for which a new
        // subset can be generated
        int left = -1;
 
        // Stores index of
        // the query[] array
        int j = 3;
 
        // Iterate over the
        // range [low, high]
        while (low <= high) {
 
            // If low is present in
            // any of the subset
            if (visited[low]) {
 
                // If no subset created for
                // the subarray arr[left...low - 1]
                if (left != -1) {
 
                    // Create a new subset
                    newUnion(left, low - 1,
                             arr.Length);
 
                    // Update left
                    left = -1;
                }
 
                // Stores next index to be
                // processed
                int jump = findJumpLength(low);
 
                // Update low
                low += jump;
 
                // Update j
                j += jump;
            }
 
            // If arr[low] has been
            // already replaced P times
            else if (count[low] == P) {
 
                // If already subset
                // created for left
                if (left == -1) {
 
                    // Update left
                    left = low;
                }
 
                // Mark low as an element
                // of any subset
                visited[low] = true;
 
                // Update low
                low++;
 
                // Update j
                j++;
            }
 
            // If arr[low] has been replaced
            // less than P times
            else {
 
                // If no subset created for
                // the subarray arr[left...low - 1]
                if (left != -1) {
 
                    // Create a new subset
                    newUnion(left, low - 1, arr.Length);
 
                    // Update left
                    left = -1;
                }
 
                // Replace arr[low] with
                // the corresponding value
                arr[low] = query[j];
 
                // Update count[low]
                count[low]++;
 
                // Update low
                low++;
 
                // Update j
                j++;
            }
        }
 
        // If no subset has been created for
        // the subarray arr[left...low - 1]
        if (left != -1) {
 
            // Create a new subset
            newUnion(left, high, arr.Length);
        }
    }
 
    // Function to find the next index
    // to be processed after visiting low
    static int findJumpLength(int low)
    {
 
        // Stores smallest index of
        // the subset where low present
        int p = findParent(low);
 
        // Stores next index
        // to be processed
        int nextIndex = last[p] + 1;
 
        // Stores difference between
        // low and nextIndex
        int jump = (nextIndex - low);
 
        // Return jump
        return jump;
    }
 
    // Function to create a new subset
    static void newUnion(int low, int high,
                         int N)
    {
 
        // Iterate over
        // the range [low + 1, high]
        for (int i = low + 1; i <= high;
             i++) {
 
            // Perform union operation
            // on low
            union(low, i);
        }
 
        // If just smaller element of low
        // is present in any of the subset
        if (low > 0 && visited[low - 1]) {
 
            // Perform union on (low - 1)
            union(low - 1, low);
        }
 
        // If just greater element of high
        // is present in any of the subset
        if (high < N - 1 && visited[high + 1]) {
 
            // Perform union on high
            union(high, high + 1);
        }
    }
 
    // Function to find the smallest
    // element of the subset
    static int findParent(int u)
    {
 
        // Base Case
        if (parent[u] == u)
            return u;
 
        // Stores smallest element
        // of parent[u
        return parent[u]
            = findParent(parent[u]);
    }
 
    // Function to perform union operation
    static void union(int u, int v)
    {
        // Stores smallest element
        // of subset containing u
        int p1 = findParent(u);
 
        // Stores smallest element
        // of subset containing u
        int p2 = findParent(v);
 
        // Update parent[p2]
        parent[p2] = p1;
 
        // Update last[p1]
        last[p1] = last[p2];
    }
 
    // Function to find all the queries
    static List<List<int> > getQueries()
    {
 
        // Stores all the queries
        List<List<int> > Q
            = new List<List<int> >();
 
        // Initialize all queries
        int[] query1 = { 1, 0, 3, 3, 2,
                             1, 11 };
        int[] query2 = { 2, 3 };
        int[] query3 = { 1, 2, 3, 5, 7 };
        int[] query4 = { 2, 2 };
 
        // Insert all queries        
        Q.Add(new List<int>(query1));
        Q.Add(new List<int>(query2));
        Q.Add(new List<int>(query3));
        Q.Add(new List<int>(query4));
 
        // Return all queries
        return Q;
    }
 
    // Driver Code
    public static void Main(String[] args)
    {
 
        int[] arr = { 3, 10, 4, 2, 8, 7 };
        int N = arr.Length;
        int P = 1;
 
        parent = new int[N];
        last = new int[N];
        count = new int[N];
        visited = new bool[N];
 
        // Initialize parent[] and
        // last[] array
        for (int i = 0; i < parent.Length;
             i++) {
 
            // Update parent[i]
            parent[i] = i;
 
            // Update last[i]
            last[i] = i;
        }
 
        List<List<int> > Q = getQueries();
        processQueries(arr, P, Q);
    }
}
 
// This code is contributed by Amit Katiyar

chevron_right


Output: 

11
1

 

Time Complexity: O(N + |Q| * P)
Auxiliary Space: O(N)

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.

My Personal Notes arrow_drop_up
Recommended Articles
Page :