# Count of divisors of product of an Array in range L to R for Q queries

Given an array arr of size N and Q queries of the form [L, R], the task is to find the number of divisors of the product of this array in the given range.

Note: The ranges are 1-positioned.

Examples:

Input: arr[] = {4, 1, 9, 12, 5, 3}, Q = {{1, 3}, {3, 5}}
Output: 9
24

Input: arr[] = {5, 2, 3, 1, 4}, Q = {{2, 4}, {1, 5}}
Output: 4
16

Brute force:

1. For every Query, iterate array from L to R and calculate the product of elements in the given range.
2. Calculate the total number of divisors of that product.

Time Complexity: Q * N * (log (N))

Efficient Approach: The idea is to use Segment Tree to solve this problem.

1. We can’t store the product of array from L to R because of the constraints so we can store the power of prime in segment tree.
2. For every query, we merge the trees according to the query.

Construction of Segment Tree from given array

• Every time we divide the current segment into two halves, if it has not yet become a segment of length 1.
• Then call the same procedure on both halves, and for each such segment, we store the power of primes in the corresponding node.
• All levels of the constructed segment tree will be completely filled except the last level.
• Also, the tree will be a Full Binary Tree because we always divide segments into two halves at every level.
• Since the constructed tree is always a full binary tree with n leaves, there will be n-1 internal nodes. So the total number of nodes will be 2*n – 1.

Below is the implementation of the above approach.

 `#include ` `using` `namespace` `std; ` `#define ll long long int ` `#define MOD 1000000007 ` ` `  `#define MAXN 1000001 ` ` `  `// Array to store the precomputed prime numbers ` `int` `spf[MAXN]; ` ` `  `// Function signatures ` `void` `merge( ` `    ``vector > tree[], ``int` `treeIndex); ` `void` `sieve(); ` `vector<``int``> getFactorization( ` `    ``int` `x); ` `void` `buildTree( ` `    ``vector > tree[], ``int` `treeIndex, ` `    ``int` `start, ``int` `end, ``int` `arr[]); ` `int` `query( ` `    ``vector > tree[], ``int` `treeIndex, ` `    ``int` `start, ``int` `end, ` `    ``int` `left, ``int` `right); ` `vector > mergeUtil( ` `    ``vector > op1, ` `    ``vector > op2); ` `vector > queryUtil( ` `    ``vector > tree[], ``int` `treeIndex, ` `    ``int` `start, ``int` `end, ` `    ``int` `left, ``int` `right); ` ` `  `// Function to use Sieve to compute ` `// and store prime numbers ` `void` `sieve() ` `{ ` `    ``spf = 1; ` `    ``for` `(``int` `i = 2; i < MAXN; i++) ` `        ``spf[i] = i; ` ` `  `    ``for` `(``int` `i = 4; i < MAXN; i += 2) ` `        ``spf[i] = 2; ` ` `  `    ``for` `(``int` `i = 3; i * i < MAXN; i++) { ` `        ``if` `(spf[i] == i) { ` `            ``for` `(``int` `j = i * i; j < MAXN; j += i) ` `                ``if` `(spf[j] == j) ` `                    ``spf[j] = i; ` `        ``} ` `    ``} ` `} ` ` `  `// Function to find the ` `// prime factors of a value ` `vector<``int``> getFactorization(``int` `x) ` `{ ` ` `  `    ``// Vectore to store the prime factors ` `    ``vector<``int``> ret; ` ` `  `    ``// For every prime factor of x, ` `    ``// push it to the vector ` `    ``while` `(x != 1) { ` ` `  `        ``ret.push_back(spf[x]); ` `        ``x = x / spf[x]; ` `    ``} ` ` `  `    ``// Return the prime factors ` `    ``return` `ret; ` `} ` ` `  `// Recursive function to build segment tree ` `// by merging the power pf primes ` `void` `buildTree(vector > tree[], ` `               ``int` `treeIndex, ``int` `start, ` `               ``int` `end, ``int` `arr[]) ` `{ ` ` `  `    ``// Base case ` `    ``if` `(start == end) { ` ` `  `        ``int` `val = arr[start]; ` `        ``vector<``int``> primeFac ` `            ``= getFactorization(val); ` ` `  `        ``for` `(``auto` `it : primeFac) { ` `            ``int` `power = 0; ` `            ``while` `(val % it == 0) { ` `                ``val = val / it; ` `                ``power++; ` `            ``} ` ` `  `            ``// Storing powers of prime ` `            ``// in tree at treeIndex ` `            ``tree[treeIndex] ` `                ``.push_back({ it, power }); ` `        ``} ` `        ``return``; ` `    ``} ` ` `  `    ``int` `mid = (start + end) / 2; ` ` `  `    ``// Building the left tree ` `    ``buildTree(tree, 2 * treeIndex, start, ` `              ``mid, arr); ` ` `  `    ``// Building the right tree ` `    ``buildTree(tree, 2 * treeIndex + 1, ` `              ``mid + 1, end, arr); ` ` `  `    ``// Merges the right tree and left tree ` `    ``merge(tree, treeIndex); ` ` `  `    ``return``; ` `} ` ` `  `// Function to merge the right ` `// and the left tree ` `void` `merge(vector > tree[], ` `           ``int` `treeIndex) ` `{ ` `    ``int` `index1 = 0; ` `    ``int` `index2 = 0; ` `    ``int` `len1 = tree[2 * treeIndex].size(); ` `    ``int` `len2 = tree[2 * treeIndex + 1].size(); ` ` `  `    ``// Fill this array in such a way such that values ` `    ``// of prime remain sorted similar to mergesort ` `    ``while` `(index1 < len1 && index2 < len2) { ` ` `  `        ``// If both of the elements are same ` `        ``if` `(tree[2 * treeIndex][index1].first ` `            ``== tree[2 * treeIndex + 1][index2].first) { ` ` `  `            ``tree[treeIndex].push_back( ` `                ``{ tree[2 * treeIndex][index1].first, ` `                  ``tree[2 * treeIndex][index1].second ` `                      ``+ tree[2 * treeIndex + 1] ` `                            ``[index2] ` `                                ``.second }); ` `            ``index1++; ` `            ``index2++; ` `        ``} ` ` `  `        ``// If the element on the left part ` `        ``// is greater than the right part ` `        ``else` `if` `(tree[2 * treeIndex][index1].first ` `                 ``> tree[2 * treeIndex + 1][index2].first) { ` ` `  `            ``tree[treeIndex].push_back( ` `                ``{ tree[2 * treeIndex + 1][index2].first, ` `                  ``tree[2 * treeIndex + 1][index2].second }); ` `            ``index2++; ` `        ``} ` ` `  `        ``// If the element on the left part ` `        ``// is less than the right part ` `        ``else` `{ ` `            ``tree[treeIndex].push_back( ` `                ``{ tree[2 * treeIndex][index1].first, ` `                  ``tree[2 * treeIndex][index1].second }); ` `            ``index1++; ` `        ``} ` `    ``} ` ` `  `    ``// Insert the leftover elements ` `    ``// from the left part ` `    ``while` `(index1 < len1) { ` `        ``tree[treeIndex].push_back( ` `            ``{ tree[2 * treeIndex][index1].first, ` `              ``tree[2 * treeIndex][index1].second }); ` `        ``index1++; ` `    ``} ` ` `  `    ``// Insert the leftover elements ` `    ``// from the right part ` `    ``while` `(index2 < len2) { ` `        ``tree[treeIndex].push_back( ` `            ``{ tree[2 * treeIndex + 1][index2].first, ` `              ``tree[2 * treeIndex + 1][index2].second }); ` `        ``index2++; ` `    ``} ` `    ``return``; ` `} ` ` `  `// Function similar to merge() method ` `// But here it takes two vectors and ` `// return a vector of power of primes ` `vector > mergeUtil( ` `    ``vector > op1, ` `    ``vector > op2) ` `{ ` `    ``int` `index1 = 0; ` `    ``int` `index2 = 0; ` `    ``int` `len1 = op1.size(); ` `    ``int` `len2 = op2.size(); ` `    ``vector > res; ` ` `  `    ``while` `(index1 < len1 && index2 < len2) { ` ` `  `        ``if` `(op1[index1].first == op2[index2].first) { ` `            ``res.push_back({ op1[index1].first, ` `                            ``op1[index1].second ` `                                ``+ op2[index2].second }); ` `            ``index1++; ` `            ``index2++; ` `        ``} ` ` `  `        ``else` `if` `(op1[index1].first > op2[index2].first) { ` `            ``res.push_back({ op2[index2].first, ` `                            ``op2[index2].second }); ` `            ``index2++; ` `        ``} ` `        ``else` `{ ` `            ``res.push_back({ op1[index1].first, ` `                            ``op1[index1].second }); ` `            ``index1++; ` `        ``} ` `    ``} ` `    ``while` `(index1 < len1) { ` `        ``res.push_back({ op1[index1].first, ` `                        ``op1[index1].second }); ` `        ``index1++; ` `    ``} ` `    ``while` `(index2 < len2) { ` `        ``res.push_back({ op2[index2].first, ` `                        ``op2[index2].second }); ` `        ``index2++; ` `    ``} ` `    ``return` `res; ` `} ` ` `  `// Function similar to query() method ` `// as in segment tree ` `// Here also the result is merged ` `vector > queryUtil( ` `    ``vector > tree[], ` `    ``int` `treeIndex, ``int` `start, ` `    ``int` `end, ``int` `left, ``int` `right) ` `{ ` `    ``if` `(start > right || end < left) { ` `        ``tree.clear(); ` `        ``return` `tree; ` `    ``} ` `    ``if` `(start >= left && end <= right) { ` `        ``return` `tree[treeIndex]; ` `    ``} ` `    ``int` `mid = (start + end) / 2; ` ` `  `    ``vector > op1 ` `        ``= queryUtil(tree, 2 * treeIndex, ` `                    ``start, mid, ` `                    ``left, right); ` `    ``vector > op2 ` `        ``= queryUtil(tree, 2 * treeIndex + 1, ` `                    ``mid + 1, end, ` `                    ``left, right); ` ` `  `    ``return` `mergeUtil(op1, op2); ` `} ` ` `  `// Function to return the number of divisors ` `// of product of array from left to right ` `int` `query(vector > tree[], ` `          ``int` `treeIndex, ``int` `start, ` `          ``int` `end, ``int` `left, ``int` `right) ` `{ ` `    ``vector > res ` `        ``= queryUtil(tree, treeIndex, ` `                    ``start, end, ` `                    ``left, right); ` ` `  `    ``int` `sum = 1; ` `    ``for` `(``auto` `it : res) { ` `        ``sum *= (it.second + 1); ` `        ``sum %= MOD; ` `    ``} ` `    ``return` `sum; ` `} ` ` `  `// Function to solve queries ` `void` `solveQueries( ` `    ``int` `arr[], ``int` `len, ` `    ``int` `l, ``int` `r) ` `{ ` ` `  `    ``// Calculate the size of segment tree ` `    ``int` `x = (``int``)(``ceil``(log2(len))); ` ` `  `    ``// Maximum size of segment tree ` `    ``int` `max_size = 2 * (``int``)``pow``(2, x) - 1; ` ` `  `    ``// first of pair is used to store the prime ` `    ``// second of pair is use to store its power ` `    ``vector > tree[max_size]; ` ` `  `    ``// building the tree ` `    ``buildTree(tree, 1, 0, len - 1, arr); ` ` `  `    ``// Find the required number of divisors ` `    ``// of product of array from l to r ` `    ``cout << query(tree, 1, 0, ` `                  ``len - 1, l - 1, r - 1) ` `         ``<< endl; ` `} ` ` `  `// Driver code ` `int` `main() ` `{ ` ` `  `    ``// Precomputing the prime numbers using sieve ` `    ``sieve(); ` ` `  `    ``int` `arr[] = { 5, 2, 3, 1, 4 }; ` `    ``int` `len = ``sizeof``(arr) / ``sizeof``(arr); ` `    ``int` `queries = 2; ` `    ``int` `Q[queries] = { { 2, 4 }, { 1, 5 } }; ` ` `  `    ``// Solve the queries ` `    ``for` `(``int` `i = 0; i < queries; i++) { ` `        ``solveQueries(arr, len, Q[i], Q[i]); ` `    ``} ` `    ``return` `0; ` `} `

Output:

```4
16
```

Time Complexity: Q * (log (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.

My Personal Notes arrow_drop_up Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.

Article Tags :

1

Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.