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 + " ");
}
}
}