Given an array arr[] of the size of N followed by an array of Q queries, of the following two types:
Note:_ Every first index of the subquery determines the type of query to be answered._
**Example: **
_Input: _arr[] = {1, 3, 5, 7, 9, 11}, Q = { { 1, 1, 3}, {2, 1, 10}, {1, 1, 3 } }
_Output: _
15
12
_Explanation: _
First query is of type 1, so answer is (3 + 5 + 7), = 15
Second query is of type 2, so arr[1] = 10
Third query is of type 1, where arr[1] = 10, which is not prime hence answer is (5 + 7) = 12
Input:_ arr[] = {1, 2, 35, 7, 14, 11}, Q = { {2, 4, 3}, {1, 4, 5 } }_
Output:_ 14_
Explanation:
First query is of type 2, So update arr[4] = 3
Second query is of type 1, since arr[4] = 3, which is prime. So answer is (3 + 11) = 14
**Naive Approach: **The idea is to iterate for each query between L to R and perform the required operation on the given array.
_Time Complexity: _O(Q * N * (O(sqrt(max(arr[i]))
**Approach: ** To optimize the problem use Segment tree and Sieve Of Eratosthenes.
// C++ program for the above approach
#include <bits/stdc++.h>
**using**
**namespace**
std;
**int**
**const**
MAX = 1000001;
**bool**
prime[MAX];
// Function to find the prime numbers
**void**
SieveOfEratosthenes()
{
// Create a boolean array prime[]
// and initialize all entries it as true
// A value in prime[i] will
// finally be false if i is Not a prime
**memset**``(prime,
**true**``,
**sizeof**``(prime));
**for**
(``**int**
p = 2; p * p <= MAX; p++) {
// Check if prime[p] is not
// changed, then it is a prime
**if**
(prime[p] ==
**true**``) {
// Update all multiples of p
// greater than or equal to
// the square of it numbers
// which are multiple of p
// and are less than p^2 are
// already been marked
**for**
(``**int**
i = p * p; i <= MAX; i += p)
prime[i] =
**false**``;
}
}
}
// Function to get the middle
// index from corner indexes
**int**
getMid(``**int**
s,
**int**
e)
{
**return**
s + (e - s) / 2;
}
// Function to get the sum of
// values in the given range
// of the array
**int**
getSumUtil(``**int**``* st,
**int**
ss,
**int**
se,
**int**
qs,
**int**
qe,
**int**
si)
{
// If segment of this node is a
// part of given range, then
// return the sum of the segment
**if**
(qs <= ss && qe >= se)
**return**
st[si];
// 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**
getSumUtil(st, ss, mid,
qs, qe,
2 * si + 1)
+ getSumUtil(st, mid + 1,
se, qs, qe,
2 * si + 2);
}
// Function to update the nodes which
// have the given index in their range
**void**
updateValueUtil(``**int**``* st,
**int**
ss,
**int**
se,
**int**
i,
**int**
diff,
**int**
si)
{
// 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, then update
// the value of the node and its children
st[si] = st[si] + diff;
**if**
(se != ss) {
**int**
mid = getMid(ss, se);
updateValueUtil(st, ss, mid, i,
diff, 2 * si + 1);
updateValueUtil(st, mid + 1,
se, i, diff,
2 * si + 2);
}
}
// Function to update a value in
// input array and segment tree
**void**
updateValue(``**int**
arr[],
**int**``* st,
**int**
n,
**int**
i,
**int**
new_val)
{
// Check for erroneous input index
**if**
(i < 0 || i > n - 1) {
cout <<
"-1"``;
**return**``;
}
// Get the difference between
// new value and old value
**int**
diff = new_val - arr[i];
**int**
prev_val = arr[i];
// Update the value in array
arr[i] = new_val;
// Update the values of
// nodes in segment tree
// only if either previous
// value or new value
// or both are prime
**if**
(prime[new_val]
|| prime[prev_val]) {
// If only new value is prime
**if**
(!prime[prev_val])
updateValueUtil(st, 0, n - 1,
i, new_val, 0);
// If only new value is prime
**else**
**if**
(!prime[new_val])
updateValueUtil(st, 0, n - 1,
i, -prev_val, 0);
// If both are prime
**else**
updateValueUtil(st, 0, n - 1,
i, diff, 0);
}
}
// Return sum of elements in range
// from index qs (quey start) to qe
// (query end). It mainly uses getSumUtil()
**int**
getSum(``**int**``* st,
**int**
n,
**int**
qs,
**int**
qe)
{
// Check for erroneous input values
**if**
(qs < 0 || qe > n - 1 || qs > qe) {
cout <<
"-1"``;
**return**
-1;
}
**return**
getSumUtil(st, 0, n - 1,
qs, qe, 0);
}
// Function that constructs Segment Tree
**int**
constructSTUtil(``**int**
arr[],
**int**
ss,
**int**
se,
**int**``* st,
**int**
si)
{
// If there is one element in
// array, store it in current node of
// segment tree and return
**if**
(ss == se) {
// Only add those elements in segment
// tree which are prime
**if**
(prime[arr[ss]])
st[si] = arr[ss];
**else**
st[si] = 0;
**return**
st[si];
}
// If there are more than one
// elements, then recur for left and
// right subtrees and store the
// sum of values in this node
**int**
mid = getMid(ss, se);
st[si]
= constructSTUtil(arr, ss, mid,
st, si * 2 + 1)
+ constructSTUtil(arr, mid + 1,
se, st,
si * 2 + 2);
**return**
st[si];
}
// Function to construct segment
// tree from given array
**int**``* constructST(``**int**
arr[],
**int**
n)
{
// Allocate memory for the segment tree
// Height of segment tree
**int**
x = (``**int**``)(``**ceil**``(log2(n)));
// Maximum size of segment tree
**int**
max_size = 2 * (``**int**``)``**pow**``(2, x) - 1;
// Allocate memory
**int**``* st =
**new**
**int**``[max_size];
// Fill the allocated memory st
constructSTUtil(arr, 0, n - 1, st, 0);
// Return the constructed segment tree
**return**
st;
}
// Driver code
**int**
main()
{
**int**
arr[] = { 1, 3, 5, 7, 9, 11 };
**int**
n =
**sizeof**``(arr) /
**sizeof**``(arr[0]);
**int**
Q[3][3]
= { { 1, 1, 3 },
{ 2, 1, 10 },
{ 1, 1, 3 } };
// Function call
SieveOfEratosthenes();
// Build segment tree from given array
**int**``* st = constructST(arr, n);
// Print sum of values in
// array from index 1 to 3
cout << getSum(st, n, 1, 3) << endl;
// Update: set arr[1] = 10
// and update corresponding
// segment tree nodes
updateValue(arr, st, n, 1, 10);
// Find sum after the value is updated
cout << getSum(st, n, 1, 3) << endl;
**return**
0;
}
Output:
15
12
Time Complexity:_ O(Q * log 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.
#advanced data structure #arrays #dynamic programming #hash #mathematical #tree #array-range-queries #prime number #segment-tree #sieve