Open In App

Number of primes in a subarray (with updates)

Last Updated : 27 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

You are given an array arr[] of size n. Your task is to process q queries, each consisting of three integers, of the following two types:

  1. [1, l, r]: Find the number of prime numbers in the subarray arr[l…r] (inclusive).
  2. [2, i, x]: Update the element at index i to x(i.e., set arr[i] = x).

Examples:  

Input: n = 6, q = 3
arr[] = [1, 2, 3, 5, 7, 9]
queries[][] = [ [1, 0, 4], [2, 3, 6], [1, 0, 4] ]
Output: 4 3
Explanation: For the query 1, the number of primes in range [0, 4] are 4 (2, 3, 5, 7). 
For the query 2, after an update, the array becomes [1, 2, 3, 6, 7, 9].
For the query 3, the number of primes in range [0, 4] are 3 (2, 3, 7). 

[Naive Approach] – Check all Numbers One by One

The idea is to treat each query as either a prime-counting operation over a subarray or an update to a single element. For a counting query, we scan through the specified range [L, R], use trial division to test each element for primality, and keep a running total of how many primes we encounter. For an update query, we simply overwrite the array at the given index with the new value.

Time Complexity Analysis: For every query, we need to consider all numbers in the range and for every number, we need to check if it is prime. An upper bound on time complexity is O(q n sqrt(MAX)), Here MAX is the maximum element in range and a range may have at most n elements.

Below is given the implementation:

C++
#include <bits/stdc++.h>
using namespace std;

// Function to check if a number is prime
bool isPrime(int n) {
    if(n <= 1) return false;
    for(int i = 2; i * i <= n; i++) {
        if(n % i == 0) return false;
    }
    return true;
}

vector<int> solveQueries(vector<int> &arr, 
                vector<vector<int>> &queries) {
    int n = arr.size();

    // to store the result of query of type 1
    vector<int> res;

    // process all the queries
    for(auto query: queries) {

        // to find the maximum 
        // product in the range [L, R]
        if(query[0] == 1) {
            int l = query[1];
            int r = query[2];
            int cnt = 0;

            // find all primes in the range [L, R]
            for(int i = l; i <= r; i++) {
                if(isPrime(arr[i])) {
                    cnt++;
                }
            }

            res.push_back(cnt);
        }

        // else update the value of arr[i]
        else if(query[0] == 2) {
            int i = query[1];
            int x = query[2];
            arr[i] = x;
        }
    }

    return res;
}

int main() {
    vector<int> arr = {1, 2, 3, 5, 7, 9};
    vector<vector<int>> queries = 
    { {1, 0, 4}, {2, 3, 6}, {1, 0, 4}};
    vector<int> res = solveQueries(arr, queries);
    for(auto i:res) {
        cout << i << " ";
    }
    return 0;
}
Java
import java.util.*;

public class GfG {

    
    // Function to check if a number is prime
    public static boolean isPrime(int n) {
        if(n <= 1) return false;
        for(int i = 2; i * i <= n; i++) {
            if(n % i == 0) return false;
        }
        return true;
    }

    public static List<Integer> solveQueries(List<Integer> arr, 
                List<List<Integer>> queries) {
        int n = arr.size();

        
        // to store the result of query of type 1
        List<Integer> res = new ArrayList<>();

        
        // process all the queries
        for(List<Integer> query: queries) {

            
            // to find the maximum 
            // product in the range [L, R]
            if(query.get(0) == 1) {
                int l = query.get(1);
                int r = query.get(2);
                int cnt = 0;

                
                // find all primes in the range [L, R]
                for(int i = l; i <= r; i++) {
                    if(isPrime(arr.get(i))) {
                        cnt++;
                    }
                }

                res.add(cnt);
            }

            
            // else update the value of arr[i]
            else if(query.get(0) == 2) {
                int i = query.get(1);
                int x = query.get(2);
                arr.set(i, x);
            }
        }

        return res;
    }

    public static void main(String[] args) {
        List<Integer> arr = Arrays.asList(1, 2, 3, 5, 7, 9);
        List<List<Integer>> queries = Arrays.asList(
            Arrays.asList(1, 0, 4), Arrays.asList(2, 3, 6), 
            Arrays.asList(1, 0, 4));
        List<Integer> res = solveQueries(arr, queries);
        for(int i:res) {
            System.out.print(i + " ");
        }
    }
}
Python
    
# Function to check if a number is prime
def isPrime(n):
    if n <= 1:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True

def solveQueries(arr, 
                queries):
    n = len(arr)

    
    # to store the result of query of type 1
    res = []

    
    # process all the queries
    for query in queries:

        
        # to find the maximum 
        # product in the range [L, R]
        if query[0] == 1:
            l = query[1]
            r = query[2]
            cnt = 0

            
            # find all primes in the range [L, R]
            for i in range(l, r + 1):
                if isPrime(arr[i]):
                    cnt += 1

            res.append(cnt)

        
        # else update the value of arr[i]
        elif query[0] == 2:
            i = query[1]
            x = query[2]
            arr[i] = x

    return res

if __name__ == "__main__":
    arr = [1, 2, 3, 5, 7, 9]
    queries = [
        [1, 0, 4], [2, 3, 6], [1, 0, 4]
    ]
    res = solveQueries(arr, queries)
    for i in res:
        print(i, end=" ")
C#
using System;
using System.Collections.Generic;

public class GfG {

    
    // Function to check if a number is prime
    public static bool isPrime(int n) {
        if(n <= 1) return false;
        for(int i = 2; i * i <= n; i++) {
            if(n % i == 0) return false;
        }
        return true;
    }

    public static List<int> solveQueries(List<int> arr, 
                List<List<int>> queries) {
        int n = arr.Count;

        
        // to store the result of query of type 1
        List<int> res = new List<int>();

        
        // process all the queries
        foreach(List<int> query in queries) {

            
            // to find the maximum 
            // product in the range [L, R]
            if(query[0] == 1) {
                int l = query[1];
                int r = query[2];
                int cnt = 0;

                
                // find all primes in the range [L, R]
                for(int i = l; i <= r; i++) {
                    if(isPrime(arr[i])) {
                        cnt++;
                    }
                }

                res.Add(cnt);
            }

            
            // else update the value of arr[i]
            else if(query[0] == 2) {
                int i = query[1];
                int x = query[2];
                arr[i] = x;
            }
        }

        return res;
    }

    public static void Main(string[] args) {
        List<int> arr = new List<int> {1, 2, 3, 5, 7, 9};
        List<List<int>> queries = new List<List<int>> {
            new List<int> {1, 0, 4}, 
            new List<int> {2, 3, 6}, new List<int> {1, 0, 4}
        };
        List<int> res = solveQueries(arr, queries);
        foreach(int i in res) {
            Console.Write(i + " ");
        }
    }
}
JavaScript
    
// Function to check if a number is prime
function isPrime(n) {
    if(n <= 1) return false;
    for(let i = 2; i * i <= n; i++) {
        if(n % i == 0) return false;
    }
    return true;
}

function solveQueries(arr, 
                queries) {
    let n = arr.length;

    
    // to store the result of query of type 1
    let res = [];

    
    // process all the queries
    for(let query of queries) {

        
        // to find the maximum 
        // product in the range [L, R]
        if(query[0] == 1) {
            let l = query[1];
            let r = query[2];
            let cnt = 0;

            
            // find all primes in the range [L, R]
            for(let i = l; i <= r; i++) {
                if(isPrime(arr[i])) {
                    cnt++;
                }
            }

            res.push(cnt);
        }

        
        // else update the value of arr[i]
        else if(query[0] == 2) {
            let i = query[1];
            let x = query[2];
            arr[i] = x;
        }
    }

    return res;
}

let arr = [1, 2, 3, 5, 7, 9];
let queries = [ [1, 0, 4], [2, 3, 6], [1, 0, 4] ];
let res = solveQueries(arr, queries);
for(let i of res) {
    process.stdout.write(i + " ");
}

Output
4 3 

[Better Approach] – Sieve of Eratosthenes

We can use Sieve of Eratosthenes to preprocess all the primes till the maximum value arri can take say MAX in O(MAX log(log(MAX)). After we have built the isPrime array till MAX, we can answer every range query in O(n) time.

[Expected Approach] – Using Segment Tree

We basically reduce the problem to subarray sum using segment tree. Now, we can build the segment tree where a leaf node is represented as either 0 (if it is not a prime number) or 1 (if it is a prime number).
The internal nodes of the segment tree equal to the sum of its child nodes, thus a node represents the total primes in the range from L to R where the range L to R falls under this node and the sub-tree below it.

Handling Queries and Point Updates: Whenever we get a query from start to end, then we can query the segment tree for the sum of nodes in range start to end, which in turn represent the number of primes in range start to end. 

If we need to perform a point update and update the value at index i to x, then we check for the following cases: 

If we need to perform a point update and update the value at index i to x, then we check for the following cases: 

Let the old value of arr[i] be y and the new value be x

Case 1: If x and y both are primes
Count of primes in the subarray does not change so we just update array and do not modify the segment tree

Case 2: If x and y both are non primes
Count of primes in the subarray does not change so we just update array and do not modify the segment tree

Case 3: If y is prime but x is non prime
Count of primes in the subarray decreases so we update array and add -1 to every range, the index i which is to be updated, is a part of in the segment tree

Case 4: If y is non prime but x is prime
Count of primes in the subarray increases so we update array and add 1 to every range, the index i which is to be updated, is a part of in the segment tree

Follow the below given steps:

  • Precompute a boolean array primes[] up to the maximum value in array using the Sieve of Eratosthenes so that primes[x] is 1 if x is prime, else 0.
  • To build the segment tree over arr[0…n-1], recursively:
    • If the segment is a single index i, set the leaf to primes[arr[i]].
    • Otherwise, split at mid = (ss+se)/2, build left and right children, and set the node’s value to the sum of its two children.
  • To answer a query for the number of primes in [L, R], traverse the tree:
    • If the current node’s segment lies fully inside [L, R], return its stored sum.
    • If it lies completely outside, return 0.
    • Otherwise, recurse into both children and return the sum of their results.
  • To perform a point update at index i with new value x:
    • Let old = arr[i]; overwrite arr[i] = x.
    • If both primes[old] and primes[x] are equal (both 0 or both 1), nothing further is needed.
    • Otherwise compute diff = primes[x] - primes[old] (±1) and propagate this diff down the tree:
      • Starting at the root segment [0, n-1], if i lies in the node’s segment, add diff to that node, then recurse into the left or right child (or both when splitting) until the leaf is updated.
  • Return the list of all query answers in order once all operations are processed.

Below is given the implementation:

C++
#include <bits/stdc++.h>
using namespace std;

vector<int> findPrimes(int n) {
    vector<int> primes(n + 1, 1);
    primes[0] = 0;
    primes[1] = 0;
    for (int i = 2; i * i <= n; i++) {
        if (primes[i]) {
            for (int j = i * i; j <= n; j += i) {
                primes[j] = 0;
            }
        }
    }
    return primes;
}

// A utility function to get the 
// middle index from corner indexes.
int getMid(int s, int e) {
    return s + (e - s) / 2; 
}

// A recursive function to get the number 
// of primes in a given range
int queryPrimesUtil(vector<int> &tree, 
    int ss, int se, int qs, int qe, int index) {

    // If segment of this node is a part of given range
    // then return the number of primes in the segment
    if (qs <= ss && qe >= se)
        return tree[index];

    // If segment of this node is outside the given range
    if (se < qs || ss > qe)
        return 0;

    // If a part of this segment overlaps with the given range
    int mid = getMid(ss, se);
    return queryPrimesUtil(tree, ss, mid, qs, qe, 2 * index + 1) + 
           queryPrimesUtil(tree, mid + 1, se, qs, qe, 2 * index + 2);
}

// A recursive function to update the nodes 
// which have the given index in their range.
void updateValueUtil(vector<int> &tree, 
    int ss, int se, int i, int diff, int si) {

    // Base Case: If the input index lies
    // outside the range of this segment
    if (i < ss || i > se)
        return;

    // If the input index is in range of this node,
    // update the value of the node and its children
    tree[si] = tree[si] + diff;
    if (se != ss) {
        int mid = getMid(ss, se);
        updateValueUtil(tree, ss, mid, i, diff, 2 * si + 1);
        updateValueUtil(tree, mid + 1, se, i, diff, 2 * si + 2);
    }
}

// The function to update a value in input array and segment tree.
// It uses updateValueUtil() to update the value in segment tree
void updateValue(vector<int> &arr, vector<int> &tree, 
    int n, int i, int new_val, vector<int> &primes) {

    // Check for erroneous input index
    if (i < 0 || i > n - 1) {
        printf("Invalid Input");
        return;
    }

    int diff, oldValue;

    oldValue = arr[i];

    // Update the value in array
    arr[i] = new_val;

    // Case 1: Old and new values both are primes
    if (primes[oldValue] && primes[new_val])
        return;

    // Case 2: Old and new values both non primes
    if ((!primes[oldValue]) && (!primes[new_val]))
        return;

    // Case 3: Old value was prime, new value is non prime
    if (primes[oldValue] && !primes[new_val]) {
        diff = -1;
    }

    // Case 4: Old value was non prime, new_val is prime
    if (!primes[oldValue] && primes[new_val]) {
        diff = 1;
    }

    // Update the values of nodes in segment tree
    updateValueUtil(tree, 0, n - 1, i, diff, 0);
}

// Return number of primes in range from index qs to qe
int queryPrimes(vector<int> &tree, int n, int qs, int qe) {
    return queryPrimesUtil(tree, 0, n - 1, qs, qe, 0);
}

// A recursive function that constructs Segment Tree 
// for array[ss..se].
int constructSTUtil(vector<int> &arr, int ss, 
    int se, vector<int> &tree, int si, vector<int> &primes) {

    // If there is one element in array, check if it
    // is prime then store 1 in the segment tree else
    // store 0 and return
    if (ss == se) {

        // if arr[ss] is prime
        if (primes[arr[ss]]) 
            tree[si] = 1;        
        else 
            tree[si] = 0;
        
        return tree[si];
    }

    // If there are more than one elements, then recur 
    // for left and right subtrees and store the sum 
    // of the two values in this node
    int mid = getMid(ss, se);
    tree[si] = constructSTUtil(arr, ss, mid, tree, si * 2 + 1, primes) + 
        constructSTUtil(arr, mid + 1, se, tree, si * 2 + 2, primes);
    return tree[si];
}

//Function to construct segment tree from given array. 
vector<int> constructST(vector<int> &arr, int n, vector<int> &primes) {

    // Height of segment tree
    int x = (int)(ceil(log2(n)));

    // Maximum size of segment tree
    int max_size = 2 * (int)pow(2, x) - 1;

    vector<int> tree(max_size);

    // Fill the allocated memory tree
    constructSTUtil(arr, 0, n - 1, tree, 0, primes);

    // Return the constructed segment tree
    return tree;
}

vector<int> solveQueries(vector<int> &arr, 
        vector<vector<int>> &queries) {
    int n = arr.size();

    // to store the result of query of type 1
    vector<int> res;

    vector<int> primes = findPrimes(1000000);

    // construct segment tree from given array
    vector<int> tree = constructST(arr, n, primes);

    // process all the queries
    for(auto query: queries) {

        // to find the number of primes in the range [L, R]
        if(query[0] == 1) {
            int l = query[1];
            int r = query[2];
            int cnt = queryPrimes(tree, n, l, r);
            res.push_back(cnt);
        }

        // else update the value of arr[i]
        else if(query[0] == 2) {
            int i = query[1];
            int x = query[2];
            updateValue(arr, tree, n, i, x, primes);
        }
    }
    return res;
}

int main() {
    vector<int> arr = {1, 2, 3, 5, 7, 9};
    vector<vector<int>> queries = 
    { {1, 0, 4}, {2, 3, 6}, {1, 0, 4}};
    vector<int> res = solveQueries(arr, queries);
    for(auto i:res) {
        cout << i << " ";
    }
    return 0;
}
Java
import java.util.*;

public class GfG {

    
    // A utility function to get the 
    // middle index from corner indexes.
    public static int getMid(int s, int e) {
        return s + (e - s) / 2; 
    }

    
    // A recursive function that constructs Segment Tree 
    // for array[ss..se].
    public static int constructSTUtil(List<Integer> arr, int ss, 
        int se, List<Integer> tree, int si, List<Integer> primes) {

        // If there is one element in array, check if it
        // is prime then store 1 in the segment tree else
        // store 0 and return
        if (ss == se) {

            // if arr.get(ss) is prime
            if (primes.get(arr.get(ss)) == 1) 
                tree.set(si, 1);        
            else 
                tree.set(si, 0);
            
            return tree.get(si);
        }

        // If there are more than one elements, then recur 
        // for left and right subtrees and store the sum 
        // of the two values in this node
        int mid = getMid(ss, se);
        int left = constructSTUtil(arr, ss, mid, tree, si * 2 + 1, primes);
        int right = constructSTUtil(arr, mid + 1, se, tree, si * 2 + 2, primes);
        tree.set(si, left + right);
        return tree.get(si);
    }

    
    //Function to construct segment tree from given array. 
    public static List<Integer> constructST(List<Integer> arr, int n, List<Integer> primes) {

        // Height of segment tree
        int x = (int)(Math.ceil(Math.log(n) / Math.log(2)));

        // Maximum size of segment tree
        int max_size = 2 * (int)Math.pow(2, x) - 1;

        List<Integer> tree = new ArrayList<>(Collections.nCopies(max_size, 0));

        // Fill the allocated memory tree
        constructSTUtil(arr, 0, n - 1, tree, 0, primes);

        // Return the constructed segment tree
        return tree;
    }

    
    // A recursive function to get the number 
    // of primes in a given range
    public static int queryPrimesUtil(List<Integer> tree, 
        int ss, int se, int qs, int qe, int index) {

        // If segment of this node is a part of given range
        // then return the number of primes in the segment
        if (qs <= ss && qe >= se)
            return tree.get(index);

        // If segment of this node is outside the given range
        if (se < qs || ss > qe)
            return 0;

        // If a part of this segment overlaps with the given range
        int mid = getMid(ss, se);
        return queryPrimesUtil(tree, ss, mid, qs, qe, 2 * index + 1) + 
               queryPrimesUtil(tree, mid + 1, se, qs, qe, 2 * index + 2);
    }

    
    // A recursive function to update the nodes 
    // which have the given index in their range.
    public static void updateValueUtil(List<Integer> tree, 
        int ss, int se, int i, int diff, int si) {

        // Base Case: If the input index lies
        // outside the range of this segment
        if (i < ss || i > se)
            return;

        // If the input index is in range of this node,
        // update the value of the node and its children
        tree.set(si, tree.get(si) + diff);
        if (se != ss) {
            int mid = getMid(ss, se);
            updateValueUtil(tree, ss, mid, i, diff, 2 * si + 1);
            updateValueUtil(tree, mid + 1, se, i, diff, 2 * si + 2);
        }
    }

    
    // The function to update a value in input array and segment tree.
    // It uses updateValueUtil() to update the value in segment tree
    public static void updateValue(List<Integer> arr, List<Integer> tree, 
        int n, int i, int new_val, List<Integer> primes) {

        // Check for erroneous input index
        if (i < 0 || i > n - 1) {
            System.out.println("Invalid Input");
            return;
        }

        int diff, oldValue;

        oldValue = arr.get(i);

        // Update the value in array
        arr.set(i, new_val);

        // Case 1: Old and new values both are primes
        if (primes.get(oldValue) == 1 && primes.get(new_val) == 1)
            return;

        // Case 2: Old and new values both non primes
        if (primes.get(oldValue) == 0 && primes.get(new_val) == 0)
            return;

        // Case 3: Old value was prime, new value is non prime
        if (primes.get(oldValue) == 1 && primes.get(new_val) == 0) {
            diff = -1;
        }

        // Case 4: Old value was non prime, new_val is prime
        else {
            diff = 1;
        }

        // Update the values of nodes in segment tree
        updateValueUtil(tree, 0, n - 1, i, diff, 0);
    }

    
    // Return number of primes in range from index qs to qe
    public static int queryPrimes(List<Integer> tree, int n, int qs, int qe) {
        return queryPrimesUtil(tree, 0, n - 1, qs, qe, 0);
    }

    
    public static List<Integer> findPrimes(int n) {
        List<Integer> primes = new ArrayList<>(Collections.nCopies(n + 1, 1));
        primes.set(0, 0);
        primes.set(1, 0);
        for (int i = 2; i * i <= n; i++) {
            if (primes.get(i) == 1) {
                for (int j = i * i; j <= n; j += i) {
                    primes.set(j, 0);
                }
            }
        }
        return primes;
    }

    
    public static List<Integer> solveQueries(List<Integer> arr, 
            List<List<Integer>> queries) {
        int n = arr.size();

        // to store the result of query of type 1
        List<Integer> res = new ArrayList<>();

        List<Integer> primes = findPrimes(1000000);

        // construct segment tree from given array
        List<Integer> tree = constructST(arr, n, primes);

        // process all the queries
        for (List<Integer> query: queries) {

            // to find the number of primes in the range [L, R]
            if (query.get(0) == 1) {
                int l = query.get(1);
                int r = query.get(2);
                int cnt = queryPrimes(tree, n, l, r);
                res.add(cnt);
            }

            // else update the value of arr[i]
            else if (query.get(0) == 2) {
                int i = query.get(1);
                int x = query.get(2);
                updateValue(arr, tree, n, i, x, primes);
            }
        }
        return res;
    }

    
    public static void main(String[] args) {
        List<Integer> arr = Arrays.asList(1, 2, 3, 5, 7, 9);
        List<List<Integer>> queries = Arrays.asList(
            Arrays.asList(1, 0, 4), Arrays.asList(2, 3, 6), Arrays.asList(1, 0, 4)
        );
        List<Integer> res = solveQueries(arr, queries);
        for (int i: res) {
            System.out.print(i + " ");
        }
    }
}
Python
# A utility function to get the 
# middle index from corner indexes.
def getMid(s, e):
    return s + (e - s) // 2

# A recursive function that constructs Segment Tree 
# for array[ss..se].
def constructSTUtil(arr, ss, 
    se, tree, si, primes):

    # If there is one element in array, check if it
    # is prime then store 1 in the segment tree else
    # store 0 and return
    if ss == se:

        # if arr[ss] is prime
        if primes[arr[ss]] == 1:
            tree[si] = 1        
        else:
            tree[si] = 0
        
        return tree[si]

    # If there are more than one elements, then recur 
    # for left and right subtrees and store the sum 
    # of the two values in this node
    mid = getMid(ss, se)
    tree[si] = constructSTUtil(arr, ss, mid, tree, si * 2 + 1, primes) + \
               constructSTUtil(arr, mid + 1, se, tree, si * 2 + 2, primes)
    return tree[si]

#Function to construct segment tree from given array. 
def constructST(arr, n, primes):

    # Height of segment tree
    x = int(math.ceil(math.log(n, 2)))

    # Maximum size of segment tree
    max_size = 2 * (2 ** x) - 1

    tree = [0] * max_size

    # Fill the allocated memory tree
    constructSTUtil(arr, 0, n - 1, tree, 0, primes)

    # Return the constructed segment tree
    return tree

# A recursive function to get the number 
# of primes in a given range
def queryPrimesUtil(tree, 
    ss, se, qs, qe, index):

    # If segment of this node is a part of given range
    # then return the number of primes in the segment
    if qs <= ss and qe >= se:
        return tree[index]

    # If segment of this node is outside the given range
    if se < qs or ss > qe:
        return 0

    # If a part of this segment overlaps with the given range
    mid = getMid(ss, se)
    return queryPrimesUtil(tree, ss, mid, qs, qe, 2 * index + 1) + \
           queryPrimesUtil(tree, mid + 1, se, qs, qe, 2 * index + 2)

# A recursive function to update the nodes 
# which have the given index in their range.
def updateValueUtil(tree, 
    ss, se, i, diff, si):

    # Base Case: If the input index lies
    # outside the range of this segment
    if i < ss or i > se:
        return

    # If the input index is in range of this node,
    # update the value of the node and its children
    tree[si] = tree[si] + diff
    if se != ss:
        mid = getMid(ss, se)
        updateValueUtil(tree, ss, mid, i, diff, 2 * si + 1)
        updateValueUtil(tree, mid + 1, se, i, diff, 2 * si + 2)

# The function to update a value in input array and segment tree.
# It uses updateValueUtil() to update the value in segment tree
def updateValue(arr, tree, 
    n, i, new_val, primes):

    # Check for erroneous input index
    if i < 0 or i > n - 1:
        print("Invalid Input")
        return

    oldValue = arr[i]

    # Update the value in array
    arr[i] = new_val

    # Case 1: Old and new values both are primes
    if primes[oldValue] == 1 and primes[new_val] == 1:
        return

    # Case 2: Old and new values both non primes
    if primes[oldValue] == 0 and primes[new_val] == 0:
        return

    # Case 3: Old value was prime, new value is non prime
    if primes[oldValue] == 1 and primes[new_val] == 0:
        diff = -1

    # Case 4: Old value was non prime, new_val is prime
    if primes[oldValue] == 0 and primes[new_val] == 1:
        diff = 1

    # Update the values of nodes in segment tree
    updateValueUtil(tree, 0, n - 1, i, diff, 0)

# Return number of primes in range from index qs to qe
def queryPrimes(tree, n, qs, qe):
    return queryPrimesUtil(tree, 0, n - 1, qs, qe, 0)

def findPrimes(n):
    primes = [1] * (n + 1)
    primes[0] = 0
    primes[1] = 0
    for i in range(2, int(n ** 0.5) + 1):
        if primes[i] == 1:
            for j in range(i * i, n + 1, i):
                primes[j] = 0
    return primes

def solveQueries(arr, 
        queries):
    n = len(arr)

    # to store the result of query of type 1
    res = []

    primes = findPrimes(1000000)

    # construct segment tree from given array
    tree = constructST(arr, n, primes)

    # process all the queries
    for query in queries:

        # to find the number of primes in the range [L, R]
        if query[0] == 1:
            l = query[1]
            r = query[2]
            cnt = queryPrimes(tree, n, l, r)
            res.append(cnt)

        # else update the value of arr[i]
        elif query[0] == 2:
            i = query[1]
            x = query[2]
            updateValue(arr, tree, n, i, x, primes)
    return res

if __name__ == "__main__":
    import math

    arr = [1, 2, 3, 5, 7, 9]
    queries = [
        [1, 0, 4], [2, 3, 6], [1, 0, 4]
    ]
    res = solveQueries(arr, queries)
    for i in res:
        print(i, end=" ")
C#
using System;
using System.Collections.Generic;
using System.Linq;

public class GfG {

    
    // A utility function to get the 
    // middle index from corner indexes.
    public static int getMid(int s, int e) {
        return s + (e - s) / 2; 
    }

    
    // A recursive function that constructs Segment Tree 
    // for array[ss..se].
    public static int constructSTUtil(List<int> arr, int ss, 
        int se, List<int> tree, int si, List<int> primes) {

        // If there is one element in array, check if it
        // is prime then store 1 in the segment tree else
        // store 0 and return
        if (ss == se) {

            // if arr[ss] is prime
            if (primes[arr[ss]] == 1) 
                tree[si] = 1;        
            else 
                tree[si] = 0;
            
            return tree[si];
        }

        // If there are more than one elements, then recur 
        // for left and right subtrees and store the sum 
        // of the two values in this node
        int mid = getMid(ss, se);
        int left = constructSTUtil(arr, ss, mid, tree, si * 2 + 1, primes);
        int right = constructSTUtil(arr, mid + 1, se, tree, si * 2 + 2, primes);
        tree[si] = left + right;
        return tree[si];
    }

    
    //Function to construct segment tree from given array. 
    public static List<int> constructST(List<int> arr, int n, List<int> primes) {

        // Height of segment tree
        int x = (int)(Math.Ceiling(Math.Log(n, 2)));

        // Maximum size of segment tree
        int max_size = 2 * (int)Math.Pow(2, x) - 1;

        List<int> tree = Enumerable.Repeat(0, max_size).ToList();

        // Fill the allocated memory tree
        constructSTUtil(arr, 0, n - 1, tree, 0, primes);

        // Return the constructed segment tree
        return tree;
    }

    
    // A recursive function to get the number 
    // of primes in a given range
    public static int queryPrimesUtil(List<int> tree, 
        int ss, int se, int qs, int qe, int index) {

        // If segment of this node is a part of given range
        // then return the number of primes in the segment
        if (qs <= ss && qe >= se)
            return tree[index];

        // If segment of this node is outside the given range
        if (se < qs || ss > qe)
            return 0;

        // If a part of this segment overlaps with the given range
        int mid = getMid(ss, se);
        return queryPrimesUtil(tree, ss, mid, qs, qe, 2 * index + 1) + 
               queryPrimesUtil(tree, mid + 1, se, qs, qe, 2 * index + 2);
    }

    
    // A recursive function to update the nodes 
    // which have the given index in their range.
    public static void updateValueUtil(List<int> tree, 
        int ss, int se, int i, int diff, int si) {

        // Base Case: If the input index lies
        // outside the range of this segment
        if (i < ss || i > se)
            return;

        // If the input index is in range of this node,
        // update the value of the node and its children
        tree[si] = tree[si] + diff;
        if (se != ss) {
            int mid = getMid(ss, se);
            updateValueUtil(tree, ss, mid, i, diff, 2 * si + 1);
            updateValueUtil(tree, mid + 1, se, i, diff, 2 * si + 2);
        }
    }

    
    // The function to update a value in input array and segment tree.
    // It uses updateValueUtil() to update the value in segment tree
    public static void updateValue(List<int> arr, List<int> tree, 
        int n, int i, int new_val, List<int> primes) {

        // Check for erroneous input index
        if (i < 0 || i > n - 1) {
            Console.WriteLine("Invalid Input");
            return;
        }

        int diff, oldValue;

        oldValue = arr[i];

        // Update the value in array
        arr[i] = new_val;

        // Case 1: Old and new values both are primes
        if (primes[oldValue] == 1 && primes[new_val] == 1)
            return;

        // Case 2: Old and new values both non primes
        if (primes[oldValue] == 0 && primes[new_val] == 0)
            return;

        // Case 3: Old value was prime, new value is non prime
        if (primes[oldValue] == 1 && primes[new_val] == 0) {
            diff = -1;
        }

        // Case 4: Old value was non prime, new_val is prime
        else {
            diff = 1;
        }

        // Update the values of nodes in segment tree
        updateValueUtil(tree, 0, n - 1, i, diff, 0);
    }

    
    // Return number of primes in range from index qs to qe
    public static int queryPrimes(List<int> tree, int n, int qs, int qe) {
        return queryPrimesUtil(tree, 0, n - 1, qs, qe, 0);
    }

    
    public static List<int> findPrimes(int n) {
        List<int> primes = Enumerable.Repeat(1, n + 1).ToList();
        primes[0] = 0;
        primes[1] = 0;
        for (int i = 2; i * i <= n; i++) {
            if (primes[i] == 1) {
                for (int j = i * i; j <= n; j += i) {
                    primes[j] = 0;
                }
            }
        }
        return primes;
    }

    
    public static List<int> solveQueries(List<int> arr, 
            List<List<int>> queries) {
        int n = arr.Count;

        // to store the result of query of type 1
        List<int> res = new List<int>();

        List<int> primes = findPrimes(1000000);

        // construct segment tree from given array
        List<int> tree = constructST(arr, n, primes);

        // process all the queries
        foreach (List<int> query in queries) {

            // to find the number of primes in the range [L, R]
            if (query[0] == 1) {
                int l = query[1];
                int r = query[2];
                int cnt = queryPrimes(tree, n, l, r);
                res.Add(cnt);
            }

            // else update the value of arr[i]
            else if (query[0] == 2) {
                int i = query[1];
                int x = query[2];
                updateValue(arr, tree, n, i, x, primes);
            }
        }
        return res;
    }

    
    public static void Main(string[] args) {
        List<int> arr = new List<int> {1, 2, 3, 5, 7, 9};
        List<List<int>> queries = new List<List<int>> {
            new List<int> {1, 0, 4}, new List<int> {2, 3, 6}, new List<int> {1, 0, 4}
        };
        List<int> res = solveQueries(arr, queries);
        foreach (int i in res) {
            Console.Write(i + " ");
        }
    }
}
JavaScript
// A utility function to get the 
// middle index from corner indexes.
function getMid(s, e) {
    return s + (e - s) / 2; 
}

// A recursive function that constructs Segment Tree 
// for array[ss..se].
function constructSTUtil(arr, ss, 
    se, tree, si, primes) {

    // If there is one element in array, check if it
    // is prime then store 1 in the segment tree else
    // store 0 and return
    if (ss === se) {

        // if arr[ss] is prime
        if (primes[arr[ss]] === 1) 
            tree[si] = 1;        
        else 
            tree[si] = 0;
        
        return tree[si];
    }

    // If there are more than one elements, then recur 
    // for left and right subtrees and store the sum 
    // of the two values in this node
    const mid = getMid(ss, se);
    tree[si] = constructSTUtil(arr, ss, mid, tree, si * 2 + 1, primes) + 
               constructSTUtil(arr, mid + 1, se, tree, si * 2 + 2, primes);
    return tree[si];
}

//Function to construct segment tree from given array. 
function constructST(arr, n, primes) {

    // Height of segment tree
    const x = Math.ceil(Math.log2(n));

    // Maximum size of segment tree
    const max_size = 2 * Math.pow(2, x) - 1;

    const tree = Array(max_size).fill(0);

    // Fill the allocated memory tree
    constructSTUtil(arr, 0, n - 1, tree, 0, primes);

    // Return the constructed segment tree
    return tree;
}

// A recursive function to get the number 
// of primes in a given range
function queryPrimesUtil(tree, 
    ss, se, qs, qe, index) {

    // If segment of this node is a part of given range
    // then return the number of primes in the segment
    if (qs <= ss && qe >= se) 
        return tree[index];

    // If segment of this node is outside the given range
    if (se < qs || ss > qe) 
        return 0;

    // If a part of this segment overlaps with the given range
    const mid = getMid(ss, se);
    return queryPrimesUtil(tree, ss, mid, qs, qe, 2 * index + 1) + 
           queryPrimesUtil(tree, mid + 1, se, qs, qe, 2 * index + 2);
}

// A recursive function to update the nodes 
// which have the given index in their range.
function updateValueUtil(tree, 
    ss, se, i, diff, si) {

    // Base Case: If the input index lies
    // outside the range of this segment
    if (i < ss || i > se) 
        return;

    // If the input index is in range of this node,
    // update the value of the node and its children
    tree[si] = tree[si] + diff;
    if (se !== ss) {
        const mid = getMid(ss, se);
        updateValueUtil(tree, ss, mid, i, diff, 2 * si + 1);
        updateValueUtil(tree, mid + 1, se, i, diff, 2 * si + 2);
    }
}

// The function to update a value in input array and segment tree.
// It uses updateValueUtil() to update the value in segment tree
function updateValue(arr, tree, 
    n, i, new_val, primes) {

    // Check for erroneous input index
    if (i < 0 || i > n - 1) {
        console.log("Invalid Input");
        return;
    }

    const oldValue = arr[i];

    // Update the value in array
    arr[i] = new_val;

    // Case 1: Old and new values both are primes
    if (primes[oldValue] === 1 && primes[new_val] === 1) 
        return;

    // Case 2: Old and new values both non primes
    if (primes[oldValue] === 0 && primes[new_val] === 0) 
        return;

    let diff;
    // Case 3: Old value was prime, new value is non prime
    if (primes[oldValue] === 1 && primes[new_val] === 0) {
        diff = -1;
    }

    // Case 4: Old value was non prime, new_val is prime
    else {
        diff = 1;
    }

    // Update the values of nodes in segment tree
    updateValueUtil(tree, 0, n - 1, i, diff, 0);
}

// Return number of primes in range from index qs to qe
function queryPrimes(tree, n, qs, qe) {
    return queryPrimesUtil(tree, 0, n - 1, qs, qe, 0);
}

function findPrimes(n) {
    const primes = Array(n + 1).fill(1);
    primes[0] = 0;
    primes[1] = 0;
    for (let i = 2; i * i <= n; i++) {
        if (primes[i] === 1) {
            for (let j = i * i; j <= n; j += i) {
                primes[j] = 0;
            }
        }
    }
    return primes;
}

function solveQueries(arr, 
        queries) {
    const n = arr.length;

    // to store the result of query of type 1
    const res = [];

    const primes = findPrimes(1000000);

    // construct segment tree from given array
    const tree = constructST(arr, n, primes);

    // process all the queries
    for (const query of queries) {

        // to find the number of primes in the range [L, R]
        if (query[0] === 1) {
            const l = query[1];
            const r = query[2];
            const cnt = queryPrimes(tree, n, l, r);
            res.push(cnt);
        }

        // else update the value of arr[i]
        else if (query[0] === 2) {
            const i = query[1];
            const x = query[2];
            updateValue(arr, tree, n, i, x, primes);
        }
    }
    return res;
}

const arr = [1, 2, 3, 5, 7, 9];
const queries = [[1, 0, 4], [2, 3, 6], [1, 0, 4]];
const res = solveQueries(arr, queries);
res.forEach(i => process.stdout.write(i + " "));

Output
4 3 

Related Topic: Segment Tree



Next Article

Similar Reads