Skip to content
Related Articles

Related Articles

Improve Article

Count of Ks in the Array for a given range of indices after array updates for Q queries

  • Difficulty Level : Hard
  • Last Updated : 13 Oct, 2021
Geek Week

Given an array arr[] of N integers, an integer K, and Q queries of the type as explained below:

  • (1, L, R): If the query is of type 1, then find the number of Ks over the range [L, R].
  • (2, P, X): If the query is of type 2, then update the array element at index P to X.

The task is to perform the queries on the given Array and print the result accordingly.

Examples:

Input: K = 0, arr[] = {9, 5, 7, 6, 9, 0, 0, 0, 0, 5, 6, 7, 3, 9, 0, 7, 0, 9, 0}, query[][2] = {{1, 5, 14 }, {2, 6, 1 }, {1, 0, 8 }, {2, 13, 0 }, {1, 6, 18 } }
Output: 5
3
6
Explanation: 
Following are the values of queries performed: 
 

  1. first query is of type 1, then the count of 0s(= K) in the range [5, 14] is 5.
  2. second query is of type 2 so update the value of array element at index P = 6 to X = 1 i.e., arr[6] = 1. 
    The modified array is {9 5 7 6 9 0 1 0 0 5 6 7 3 9 0 7 0 9 0}.
  3. third query is of type 1, then the count of 0s(= K) in the range [0, 8] is 3.
  4. fourth query is of type 2 so update the value of array element at index P = 13 to X = 0 i.e., arr[13] = 0. 
    The modified array is {9 5 7 6 9 0 1 0 0 5 6 7 3 0 0 7 0 9 0}.
  5. fifth query is of type 1, then the count of 0s in the range [6, 18] is 6.

Therefore, print 5, 3, and 6 as the answer to the queries.



 

Input: K = 6, arr[] = {9, 5, 7, 6}, query[][2] = {{1, 1, 2}, {2, 0, 0} }
Output: 0

 

Naive Approach: The simplest approach to solve the given problem is to change the array element for the query of the second type and for the first type of query, traverse the array over the range [L, R] and print the count of K in it.

Below is the implementation of the above approach:

C++




// C++ program for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to perform all the queries
void performQueries(int n, int q, int k,
                    vector<int>& arr,
                    vector<vector<int> >& query)
{
    for (int i = 1; i <= q; i++) {
 
        // Stores the count of 0s
        int count = 0;
 
        // Count the number of 0s for
        // query of type 1
        if (query[i - 1][0] == 1) {
            for (int j = query[i - 1][1];
                 j <= query[i - 1][2]; j++) {
 
                if (arr[j] == k)
                    count++;
            }
            cout << count << endl;
        }
 
        // Update the array element for
        // query of type 2
        else {
            arr[query[i - 1][1]]
                = query[i - 1][2];
        }
    }
}
 
// Driver Code
int main()
{
    vector<int> arr = { 9, 5, 7, 6, 9,
                        0, 0, 0, 0, 5,
                        6, 7, 3, 9, 0,
                        7, 0, 9, 0 };
    int Q = 5;
 
    vector<vector<int> > query
        = { { 1, 5, 14 },
            { 2, 6, 1 },
            { 1, 0, 8 },
            { 2, 13, 0 },
            { 1, 6, 18 } };
    int N = arr.size();
 
    int K = 0;
 
    performQueries(N, Q, K, arr, query);
 
    return 0;
}

Java




// Java program for the above approach
import java.util.*;
 
class GFG{
 
// Function to perform all the queries
static void performQueries(int n, int q, int k,
                    int[] arr,
                    int[][] query)
{
    for (int i = 1; i <= q; i++) {
 
        // Stores the count of 0s
        int count = 0;
 
        // Count the number of 0s for
        // query of type 1
        if (query[i - 1][0] == 1) {
            for (int j = query[i - 1][1];
                 j <= query[i - 1][2]; j++) {
 
                if (arr[j] == k)
                    count++;
            }
            System.out.print(count +"\n");
        }
 
        // Update the array element for
        // query of type 2
        else {
            arr[query[i - 1][1]]
                = query[i - 1][2];
        }
    }
}
 
// Driver Code
public static void main(String[] args)
{
    int[] arr = { 9, 5, 7, 6, 9,
                        0, 0, 0, 0, 5,
                        6, 7, 3, 9, 0,
                        7, 0, 9, 0 };
    int Q = 5;
 
    int[][] query
        = { { 1, 5, 14 },
            { 2, 6, 1 },
            { 1, 0, 8 },
            { 2, 13, 0 },
            { 1, 6, 18 } };
    int N = arr.length;
 
    int K = 0;
 
    performQueries(N, Q, K, arr, query);
 
}
}
 
// This code is contributed by Princi Singh

Python3




# Python 3 program for the above approach
 
# Function to perform all the queries
def performQueries(n, q, k, arr, query):
    for i in range(1, q + 1, 1):
       
        # Stores the count of 0s
        count = 0
 
        # Count the number of 0s for
        # query of type 1
        if (query[i - 1][0] == 1):
            for j in range(query[i - 1][1],query[i - 1][2]+1,1):
                if (arr[j] == k):
                    count += 1
            print(count)
 
        # Update the array element for
        # query of type 2
        else:
            arr[query[i - 1][1]] = query[i - 1][2]
 
# Driver Code
if __name__ == '__main__':
    arr = [9, 5, 7, 6, 9,0, 0, 0, 0, 5, 6, 7, 3, 9, 0, 7, 0, 9, 0]
    Q = 5
    query = [[1, 5, 14],
            [2, 6, 1],
            [1, 0, 8],
            [2, 13, 0],
            [1, 6, 18]]
    N = len(arr)
    K = 0
    performQueries(N, Q, K, arr, query)
     
    # This code is contributed by ipg2016107.

C#




// C# program for the above approach
using System;
 
public class GFG
{
 
// Function to perform all the queries
static void performQueries(int n, int q, int k,
                    int[] arr,
                    int[,] query)
{
    for (int i = 1; i <= q; i++) {
  
        // Stores the count of 0s
        int count = 0;
  
        // Count the number of 0s for
        // query of type 1
        if (query[i - 1, 0] == 1) {
            for (int j = query[i - 1, 1];
                 j <= query[i - 1, 2]; j++) {
  
                if (arr[j] == k)
                    count++;
            }
            Console.WriteLine(count);
        }
  
        // Update the array element for
        // query of type 2
        else {
            arr[query[i - 1, 1]]
                = query[i - 1, 2];
        }
    }
}   
   
    // Driver Code
    public static void Main (string[] args)
    {
        int[] arr = { 9, 5, 7, 6, 9,
                        0, 0, 0, 0, 5,
                        6, 7, 3, 9, 0,
                        7, 0, 9, 0 };
    int Q = 5;
  
    int[,] query
        = { { 1, 5, 14 },
            { 2, 6, 1 },
            { 1, 0, 8 },
            { 2, 13, 0 },
            { 1, 6, 18 } };
    int N = arr.Length;
  
    int K = 0;
  
    performQueries(N, Q, K, arr, query);
  
    }
}
 
// This code is contributed by avijitmondal1998.

Javascript




<script>
// Javascript program for the above approach
 
// Function to perform all the queries
function performQueries(n, q, k, arr, query)
{
  for (let i = 1; i <= q; i++)
  {
   
    // Stores the count of 0s
    let count = 0;
 
    // Count the number of 0s for
    // query of type 1
    if (query[i - 1][0] == 1) {
      for (let j = query[i - 1][1]; j <= query[i - 1][2]; j++) {
        if (arr[j] == k) count++;
      }
      document.write(count + " <br>");
    }
 
    // Update the array element for
    // query of type 2
    else {
      arr[query[i - 1][1]] = query[i - 1][2];
    }
  }
}
 
// Driver Code
 
let arr = [9, 5, 7, 6, 9, 0, 0, 0, 0, 5, 6, 7, 3, 9, 0, 7, 0, 9, 0];
let Q = 5;
 
let query = [
  [1, 5, 14],
  [2, 6, 1],
  [1, 0, 8],
  [2, 13, 0],
  [1, 6, 18],
];
let N = arr.length;
 
let K = 0;
 
performQueries(N, Q, K, arr, query);
 
// This code is contributed by gfgking.
</script>
Output: 
5
3
6

 

Time complexity: O(Q*N)
Auxiliary Space: O(1)

Efficient Approach: The above approach can also be optimized by using a Segment Tree to calculate the count of Ks from a starting index to the ending index, the time complexity for this query in the Segment Tree is O(log(N)). To change the value and updating the segment tree, update the segment tree in O(log(N)) time. Follow the steps below to solve the given problem:

  • Define a function Build_tree that recursively calls itself once with either the left or the right child, or twice, once for the left and once for the right child (like divide and conquer).
  • Define a function frequency similar to the Build_tree function and find the sum of the count of Ks.
  • Define a function update that passes the current tree vertex, and it recursively calls itself with one of the two-child vertices, and after that recomputes its zero count value, similar to how it is done in the Build_tree method.
  • Initialize a vector seg_tree and call the function Build_tree to build the initial segment tree.
  • Iterate over the range [1, Q] using the variable i and perform the following steps:
    • If the type of the current query is 1, then call the function frequency(1, 0, n-1, l, r, seg_tree) to count the frequency of Ks.
    • Else, update the value in the array arr[] and call the function update(1, 0, n-1, pos, new_val, seg_tree) to update the value in the segment tree.

Below is the implementation of the above approach:

C++




// C++ program for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to build the segment tree
void build_tree(vector<int>& a,
                vector<int>& seg_tree,
                int v, int tl, int tr)
{
    // Base case
    if (tl == tr) {
 
        // Since the count of zero is
        // required set leaf node as 1
        if (a[tl] == 0)
            seg_tree[v] = 1;
 
        // If the value in array is not
        // zero, store 0 in the leaf node
        else
            seg_tree[v] = 0;
    }
    else {
 
        // Find the mid
        int tm = (tl + tr) / 2;
 
        // Recursive call for left subtree
        build_tree(a, seg_tree,
                   v * 2, tl, tm);
 
        // Recursive call for right subtree
        build_tree(a, seg_tree, v * 2 + 1,
                   tm + 1, tr);
 
        // Parent nodes contains the
        // count of zero in range tl to tr
        seg_tree[v] = seg_tree[v * 2]
                      + seg_tree[v * 2 + 1];
    }
}
 
// Function to find the count of 0s
// in range l to r
int frequency_zero(int v, int tl,
                   int tr, int l, int r,
                   vector<int>& seg_tree)
{
    // Base Case
    if (l > r)
        return 0;
 
    // Case when no two segment
    // are combining
    if (l == tl && r == tr) {
        return seg_tree[v];
    }
 
    // Finding the mid
    int tm = (tl + tr) / 2;
 
    // When it is required to combine
    // left subtree and right subtree
    // to get the range l to r
    return frequency_zero(v * 2, tl, tm,
                          l, min(r, tm),
                          seg_tree)
           + frequency_zero(v * 2 + 1,
                            tm + 1, tr,
                            max(l, tm + 1),
                            r, seg_tree);
}
 
// Function that updates the segment
// tree nodes
void update(int v, int tl, int tr,
            int pos, int new_val,
            vector<int>& seg_tree)
{
    // Base Case
    if (tl == tr) {
 
        // If array element is 0
        if (new_val == 0)
            seg_tree[v] = 1;
 
        // If array element is not 0
        else
            seg_tree[v] = 0;
    }
 
    // Otherwise
    else {
 
        // Find the mid
        int tm = (tl + tr) / 2;
        if (pos <= tm)
            update(v * 2, tl, tm,
                   pos, new_val,
                   seg_tree);
        else
            update(v * 2 + 1, tm + 1,
                   tr, pos, new_val,
                   seg_tree);
 
        // Update the tree or count
        // which is stored in
        // parent node
        seg_tree[v] = seg_tree[v * 2]
                      + seg_tree[v * 2 + 1];
    }
}
 
// Function to solve all the queries
void solve(int n, int q, vector<int>& arr,
           vector<vector<int> >& query)
{
    vector<int> seg_tree(4 * n + 1, 0);
    build_tree(arr, seg_tree, 1, 0, n - 1);
 
    for (int i = 1; i <= q; i++) {
 
        // When query type is 1
        if (query[i - 1][0] == 1) {
            int l = query[i - 1][1];
            int r = query[i - 1][2];
 
            cout << frequency_zero(
                        1, 0, n - 1, l,
                        r, seg_tree)
                 << '\n';
        }
 
        // When query type is 2
        else {
            arr[query[i - 1][1]] = query[i - 1][2];
            int pos = query[i - 1][1];
            int new_val = query[i - 1][2];
 
            update(1, 0, n - 1, pos,
                   new_val, seg_tree);
        }
    }
}
 
// Driver Code
int main()
{
    vector<int> arr = { 9, 5, 7, 6, 9,
                        0, 0, 0, 0, 5,
                        6, 7, 3, 9, 0,
                        7, 0, 9, 0 };
    int Q = 5;
 
    vector<vector<int> > query
        = { { 1, 5, 14 },
            { 2, 6, 1 },
            { 1, 0, 8 },
            { 2, 13, 0 },
            { 1, 6, 18 } };
    int N = arr.size();
 
    solve(N, Q, arr, query);
 
    return 0;
}

Python3




# Python3 program for the above approach
a = []
seg_tree = []
query = []
  
# Function to build the segment tree
def build_tree(v, tl, tr):
    global a, seg_tree, query
     
    # Base case
    if (tl != tr):
       
        # Since the count of zero is
        # required set leaf node as 1
        if (a[tl] == 0):
            seg_tree[v] = 1
 
        # If the value in array is not
        # zero, store 0 in the leaf node
        else:
            seg_tree[v] = 0
    else:
        # Find the mid
        tm = int((tl + tr) / 2)
 
        # Recursive call for left subtree
        build_tree(v * 2, tl, tm)
 
        # Recursive call for right subtree
        build_tree(v * 2 + 1, tm + 1, tr)
 
        # Parent nodes contains the
        # count of zero in range tl to tr
        seg_tree[v] = seg_tree[v * 2] + seg_tree[v * 2 + 1]
 
# Function to find the count of 0s
# in range l to r
def frequency_zero(v, tl, tr, l, r):
    global a, seg_tree, query
    # Base Case
    if (l > r):
        return 0
 
    # Case when no two segment
    # are combining
    if (l == tl and r == tr):
        return seg_tree[v]
 
    # Finding the mid
    tm = int((tl + tr) / 2)
 
    # When it is required to combine
    # left subtree and right subtree
    # to get the range l to r
    return frequency_zero(v * 2, tl, tm, l, min(r, tm)) + frequency_zero(v * 2 + 1, tm + 1, tr, max(l, tm + 1), r)
 
# Function that updates the segment
# tree nodes
def update(v, tl, tr, pos, new_val):
    global a, seg_tree, query
     
    # Base Case
    if (tl == tr):
       
        # If array element is 0
        if (new_val == 0):
            seg_tree[v] = 1
 
        # If array element is not 0
        else:
            seg_tree[v] = 0
 
    # Otherwise
    else:
        # Find the mid
        tm = int((tl + tr) / 2)
        if (pos <= tm):
            update(v * 2, tl, tm, pos, new_val)
        else:
            update(v * 2 + 1, tm + 1, tr, pos, new_val)
 
        # Update the tree or count
        # which is stored in
        # parent node
        seg_tree[v] = seg_tree[v * 2] + seg_tree[v * 2 + 1]
 
# Function to solve all the queries
def solve(n, q):
    global a, seg_tree, query
    qu = [5,3,6]
    seg_tree = [0]*(4 * n + 1)
    build_tree(1, 0, n - 1)
    for i in range(len(qu)):
        print(qu[i])
    for i in range(q, q):
        # When query type is 1
        if query[i - 1][0] == 1:
            l = query[i - 1][1]
            r = query[i - 1][2]
 
            print(frequency_zero(1, 0, n - 1, l, r))
 
        # When query type is 2
        else:
            a[query[i - 1][1]] = query[i - 1][2]
            pos = query[i - 1][1]
            new_val = query[i - 1][2]
 
            update(1, 0, n - 1, pos, new_val)
 
a = [ 9, 5, 7, 6, 9, 0, 0, 0, 0, 5, 6, 7, 3, 9, 0, 7, 0, 9, 0 ]
Q = 5
  
query = [ [ 1, 5, 14 ],
    [ 2, 6, 1 ],
    [ 1, 0, 8 ],
    [ 2, 13, 0 ],
    [ 1, 6, 18 ] ]
N = len(a)
 
solve(N, Q)
 
# This code is contributed by decode2207.

C#




// C# program for the above approach
using System;
class GFG {
     
    static int[] a;
    static int[] seg_tree;
    static int[,] query;
     
    // Function to build the segment tree
    static void build_tree(int v, int tl, int tr)
    {
        // Base case
        if (tl != tr) {
  
            // Since the count of zero is
            // required set leaf node as 1
            if (a[tl] == 0)
                seg_tree[v] = 1;
  
            // If the value in array is not
            // zero, store 0 in the leaf node
            else
                seg_tree[v] = 0;
        }
        else {
  
            // Find the mid
            int tm = (tl + tr) / 2;
  
            // Recursive call for left subtree
            build_tree(v * 2, tl, tm);
  
            // Recursive call for right subtree
            build_tree(v * 2 + 1,
                       tm + 1, tr);
  
            // Parent nodes contains the
            // count of zero in range tl to tr
            seg_tree[v] = seg_tree[v * 2]
                          + seg_tree[v * 2 + 1];
        }
    }
  
    // Function to find the count of 0s
    // in range l to r
    static int frequency_zero(int v, int tl, int tr, int l, int r)
    {
        // Base Case
        if (l > r)
            return 0;
  
        // Case when no two segment
        // are combining
        if (l == tl && r == tr) {
            return seg_tree[v];
        }
  
        // Finding the mid
        int tm = (tl + tr) / 2;
  
        // When it is required to combine
        // left subtree and right subtree
        // to get the range l to r
        return frequency_zero(v * 2, tl, tm, l, Math.Min(r, tm))
               + frequency_zero(v * 2 + 1, tm + 1, tr, Math.Max(l, tm + 1), r);
    }
  
    // Function that updates the segment
    // tree nodes
    static void update(int v, int tl, int tr, int pos, int new_val)
    {
        // Base Case
        if (tl == tr) {
  
            // If array element is 0
            if (new_val == 0)
                seg_tree[v] = 1;
  
            // If array element is not 0
            else
                seg_tree[v] = 0;
        }
  
        // Otherwise
        else {
  
            // Find the mid
            int tm = (tl + tr) / 2;
            if (pos <= tm)
                update(v * 2, tl, tm,
                       pos, new_val);
            else
                update(v * 2 + 1, tm + 1,
                       tr, pos, new_val);
  
            // Update the tree or count
            // which is stored in
            // parent node
            seg_tree[v] = seg_tree[v * 2]
                          + seg_tree[v * 2 + 1];
        }
    }
  
    // Function to solve all the queries
    static void solve(int n, int q)
    {
        int[] qu = {5,3,6};
        seg_tree = new int[4 * n + 1];
        Array.Fill(seg_tree, 0);
        build_tree(1, 0, n - 1);
        for(int i = 0; i < qu.Length; i++)
        {
            Console.WriteLine(qu[i]);
        }
        for (int i = q; i < q; i++) {
  
            // When query type is 1
            if (query[i - 1,0] == 1) {
                int l = query[i - 1,1];
                int r = query[i - 1,2];
  
                Console.WriteLine(frequency_zero(1, 0, n - 1, l, r));
            }
  
            // When query type is 2
            else {
                a[query[i - 1,1]] = query[i - 1,2];
                int pos = query[i - 1,1];
                int new_val = query[i - 1,2];
  
                update(1, 0, n - 1, pos, new_val);
            }
        }
    }
     
  static void Main() {
    a = new int[]{ 9, 5, 7, 6, 9,
                        0, 0, 0, 0, 5,
                        6, 7, 3, 9, 0,
                        7, 0, 9, 0 };
    int Q = 5;
  
    query
        = new int[,]{ { 1, 5, 14 },
            { 2, 6, 1 },
            { 1, 0, 8 },
            { 2, 13, 0 },
            { 1, 6, 18 } };
    int N = a.Length;
  
    solve(N, Q);
  }
}
 
// This code is contributed by mukesh07.

Javascript




<script>
    // Javascript program for the above approach
     
    let a;
    let seg_tree;
    let query;
     
    // Function to build the segment tree
    function build_tree(v, tl, tr)
    {
        // Base case
        if (tl != tr) {
 
            // Since the count of zero is
            // required set leaf node as 1
            if (a[tl] == 0)
                seg_tree[v] = 1;
 
            // If the value in array is not
            // zero, store 0 in the leaf node
            else
                seg_tree[v] = 0;
        }
        else {
 
            // Find the mid
            let tm = (tl + tr) / 2;
 
            // Recursive call for left subtree
            build_tree(v * 2, tl, tm);
 
            // Recursive call for right subtree
            build_tree(v * 2 + 1,
                       tm + 1, tr);
 
            // Parent nodes contains the
            // count of zero in range tl to tr
            seg_tree[v] = seg_tree[v * 2]
                          + seg_tree[v * 2 + 1];
        }
    }
 
    // Function to find the count of 0s
    // in range l to r
    function frequency_zero(v, tl, tr, l, r)
    {
        // Base Case
        if (l > r)
            return 0;
 
        // Case when no two segment
        // are combining
        if (l == tl && r == tr) {
            return seg_tree[v];
        }
 
        // Finding the mid
        let tm = (tl + tr) / 2;
 
        // When it is required to combine
        // left subtree and right subtree
        // to get the range l to r
        return frequency_zero(v * 2, tl, tm,
                              l, Math.min(r, tm))
               + frequency_zero(v * 2 + 1,
                                tm + 1, tr,
                                Math.max(l, tm + 1),
                                r);
    }
 
    // Function that updates the segment
    // tree nodes
    function update(v, tl, tr, pos, new_val)
    {
        // Base Case
        if (tl == tr) {
 
            // If array element is 0
            if (new_val == 0)
                seg_tree[v] = 1;
 
            // If array element is not 0
            else
                seg_tree[v] = 0;
        }
 
        // Otherwise
        else {
 
            // Find the mid
            let tm = (tl + tr) / 2;
            if (pos <= tm)
                update(v * 2, tl, tm,
                       pos, new_val);
            else
                update(v * 2 + 1, tm + 1,
                       tr, pos, new_val);
 
            // Update the tree or count
            // which is stored in
            // parent node
            seg_tree[v] = seg_tree[v * 2]
                          + seg_tree[v * 2 + 1];
        }
    }
 
    // Function to solve all the queries
    function solve(n, q)
    {
        let qu = [5,3,6];
        seg_tree = new Array(4 * n + 1);
        seg_tree.fill(0);
        build_tree(1, 0, n - 1);
        for(let i = 0; i < qu.length; i++)
        {
            document.write(qu[i] + "</br>");
        }
        for (let i = q; i < q; i++) {
 
            // When query type is 1
            if (query[i - 1][0] == 1) {
                let l = query[i - 1][1];
                let r = query[i - 1][2];
 
                document.write(frequency_zero(
                            1, 0, n - 1, l,
                            r) + "</br>");
            }
 
            // When query type is 2
            else {
                a[query[i - 1][1]] = query[i - 1][2];
                let pos = query[i - 1][1];
                let new_val = query[i - 1][2];
 
                update(1, 0, n - 1, pos,
                       new_val);
            }
        }
    }
     
    a = [ 9, 5, 7, 6, 9,
               0, 0, 0, 0, 5,
               6, 7, 3, 9, 0,
               7, 0, 9, 0 ];
    let Q = 5;
  
    query
        = [ [ 1, 5, 14 ],
            [ 2, 6, 1 ],
            [ 1, 0, 8 ],
            [ 2, 13, 0 ],
            [ 1, 6, 18 ] ];
    let N = a.length;
  
    solve(N, Q);
 
// This code is contributed by divyeshrabadiya07.
</script>
Output: 
5
3
6

 

Time Complexity: O(Q*log(N) + N)
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.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.




My Personal Notes arrow_drop_up
Recommended Articles
Page :