Number of primes in a subarray (with updates)
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, l, r]
: Find the number of prime numbers in the subarrayarr[l…r]
(inclusive).[2, i, x]
: Update the element at indexi
tox
(i.e., setarr[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:
#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;
}
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 + " ");
}
}
}
# 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=" ")
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 + " ");
}
}
}
// 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 thatprimes[x]
is 1 ifx
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 toprimes[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.
- If the segment is a single index
- 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.
- If the current node’s segment lies fully inside
- To perform a point update at index
i
with new valuex
:- Let
old = arr[i]
; overwritearr[i] = x
. - If both
primes[old]
andprimes[x]
are equal (both 0 or both 1), nothing further is needed. - Otherwise compute
diff = primes[x] - primes[old]
(±1) and propagate thisdiff
down the tree:- Starting at the root segment
[0, n-1]
, ifi
lies in the node’s segment, adddiff
to that node, then recurse into the left or right child (or both when splitting) until the leaf is updated.
- Starting at the root segment
- Let
- Return the list of all query answers in order once all operations are processed.
Below is given the implementation:
#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;
}
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 + " ");
}
}
}
# 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=" ")
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 + " ");
}
}
}
// 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