VOOZH about

URL: https://www.geeksforgeeks.org/dsa/number-primes-subarray-updates/

⇱ Number of primes in a subarray (with updates) - GeeksforGeeks


  • Courses
  • Tutorials
  • Interview Prep

Number of primes in a subarray (with updates)

Last Updated : 11 Jul, 2025

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:


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:


Output
4 3 

Related Topic: Segment Tree

Comment