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.
Prerequisite: MO’s Algorithm, Modular Multiplicative Inverse, Prime Factorization using sieve
Examples:
Input: arr[] = {4, 1, 9, 12, 5, 3}, Q = {{1, 3}, {3, 5}}
Output:
9
24Input: arr[] = {5, 2, 3, 1, 4}, Q = {{2, 4}, {1, 5}}
Output:
4
16
Approach:
The idea of MO’s algorithm is to preprocess all queries so that result of one query can be used in the next query.
Let a[0…n1] be input array and q[0..m1] be an array of queries.
 Sort all queries in a way that queries with L values from 0 to √n – 1 are put together, then all queries from √n to 2×√n – 1, and so on. All queries within a block are sorted in increasing order of R values.
 Process all queries one by one in a way that every query uses result computed in the previous query. Let ‘result’ be result of previous query

A number n can be represented as n = , where a_{i} are prime factors and p_{i} are integral power of them.
So, for this factorization we have formula to find total number of divisor of n and that is: 
In Add function we increment counter array as i.e counter[a[i]]=counter[a[i]]+ p_{i}. Let ‘prev’ stores the previous value of counter[a[i]]. Now as counter array changes, result changes as:
 result = result / (prev + 1) (Dividing by prev+1 neutralizes the effect of previous p_{i})
 result = (result × (counter[p_{i}] + 1) (Now the previous result is neutralized so we multiply with the new count i.e counter[a[i]]+1)

In Remove function we decrement the counter array as counter[a[i]] = counter[a[i]] – p_{i}. Now as counter array changes, result changes as:
 result = result / (prev + 1) (Dividing by prev+1 neutralizes the effect of previous p_{i})

result = (result × (counter[p_{i}] + 1) (Now the previous result is neutralized so we
multiply with the new count i.e counter[a[i]]+1)
Below is the implementation of the above approach
// C++ program to Count the divisors // of product of an Array in range // L to R for Q queries #include <bits/stdc++.h> using namespace std; #define MAX 1000000 #define MOD 1000000007 #define ll long long int // Variable to represent block size. // This is made global so compare() // of sort can use it. int block; // Structure to represent a query range struct Query { int L, R; }; // Store the prime factor of numbers // till MAX vector<pair< int , int > > store[MAX + 1]; // Initialized to store the count // of prime fators int counter[MAX + 1] = {}; // Result is Initialized to 1 int result = 1; // Inverse array to store // inverse of number from 1 to MAX ll inverse[MAX + 1]; // Function used to sort all queries so that // all queries of the same block are arranged // together and within a block, queries are // sorted in increasing order of R values. bool compare(Query x, Query y) { // Different blocks, sort by block. if (x.L / block != y.L / block) return x.L / block < y.L / block; // Same block, sort by R value return x.R < y.R; } // Function to calculate modular // inverse and storing it in Inverse array void modularInverse() { inverse[0] = inverse[1] = 1; for ( int i = 2; i <= MAX; i++) inverse[i] = inverse[MOD % i] * (MOD  MOD / i) % MOD; } // Function to use Sieve to compute // and store prime numbers void sieve() { store[1].push_back({ 1, 0 }); for ( int i = 2; i <= MAX; i++) { if (store[i].size() == 0) { store[i].push_back({ i, 1 }); for ( int j = 2 * i; j <= MAX; j += i) { int cnt = 0; int x = j; while (x % i == 0) cnt++, x /= i; store[j].push_back({ i, cnt }); } } } } // Function to Add elements // of current range void add( int currL, int a[]) { int value = a[currL]; for ( auto it = store[value].begin(); it != store[value].end(); it++) { // it>first is ai // it>second is its integral power int prev = counter[it>first]; counter[it>first] += it>second; result = (result * inverse[prev + 1]) % MOD; result = (result * (counter[it>first] + 1)) % MOD; } } // Function to remove elements // of previous range void remove ( int currR, int a[]) { int value = a[currR]; for ( auto it = store[value].begin(); it != store[value].end(); it++) { // it>first is ai // it>second is its integral power int prev = counter[it>first]; counter[it>first] = it>second; result = (result * inverse[prev + 1]) % MOD; result = (result * (counter[it>first] + 1)) % MOD; } } // Function to print the answer. void queryResults( int a[], int n, Query q[], int m) { // Find block size block = ( int ) sqrt (n); // Sort all queries so that queries of // same blocks are arranged together. sort(q, q + m, compare); // Initialize current L, current R and // current result int currL = 0, currR = 0; for ( int i = 0; i < m; i++) { // L and R values of current range int L = q[i].L, R = q[i].R; // Add Elements of current range while (currR <= R) { add(currR, a); currR++; } while (currL > L) { add(currL  1, a); currL; } // Remove element of previous range while (currR > R + 1) { remove (currR  1, a); currR; } while (currL < L) { remove (currL, a); currL++; } cout << result << endl; } } // Driver Code int main() { // Precomputing the prime numbers // using sieve sieve(); // Precomputing modular inverse of // numbers from 1 to MAX modularInverse(); int a[] = { 5, 2, 3, 1, 4 }; int n = sizeof (a) / sizeof (a[0]); Query q[] = { { 1, 3 }, { 0, 4 } }; int m = sizeof (q) / sizeof (q[0]); // Answer the queries queryResults(a, n, q, m); return 0; } 
4 16
Time Complexity: O(Q×sqrt(N))
Recommended Posts:
 Count of divisors of product of an Array in range L to R for Q queries
 Range Queries to count elements lying in a given Range : MO's Algorithm
 Array range queries over range queries
 Count of elements having odd number of divisors in index range [L, R] for Q queries
 Queries for count of even digit sum elements in given range using MO's Algorithm
 Product of proper divisors of a number for Q queries
 Count of nodes having odd divisors in the given subtree for Q queries
 Range Queries for count of Armstrong numbers in subarray using MO's algorithm
 Sum of product of proper divisors of all Numbers lying in range [L, R]
 Range product queries in an array
 Queries for elements having values within the range A to B in the given index range using Segment Tree
 Count elements in the given range which have maximum number of divisors
 Queries for count of array elements with values in given range with updates
 Maximum possible prime divisors that can exist in numbers having exactly N divisors
 Queries for elements having values within the range A to B using MO's Algorithm
 Find the XOR of the elements in the given range [L, R] with the value K for a given set of queries
 Queries to find maximum product pair in range with updates
 Find the Initial Array from given array after range sum queries
 Binary Indexed Tree : Range Update and Range Queries
 Queries for the difference between the count of composite and prime numbers in a given range
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.
Improved By : Akanksha_Rai