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.
Constraints: 1<= N, Q <= 105, 1<= arr[i] <= 106.
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
Brute force:
- For every Query, iterate array from L to R and calculate the product of elements in the given range.
- 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.
- 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.
- For every query, we merge the trees according to the query.
Construction of Segment Tree from given array
- We start with a segment arr[0 . . . n-1].
- 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 <bits/stdc++.h> 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<pair< int , int > > tree[], int treeIndex);
void sieve();
vector< int > getFactorization(
int x);
void buildTree(
vector<pair< int , int > > tree[], int treeIndex,
int start, int end, int arr[]);
int query(
vector<pair< int , int > > tree[], int treeIndex,
int start, int end,
int left, int right);
vector<pair< int , int > > mergeUtil(
vector<pair< int , int > > op1,
vector<pair< int , int > > op2);
vector<pair< int , int > > queryUtil(
vector<pair< int , int > > 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] = 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)
{ // Vector 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 of primes void buildTree(vector<pair< int , int > > 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<pair< int , int > > 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<pair< int , int > > mergeUtil(
vector<pair< int , int > > op1,
vector<pair< int , int > > op2)
{ int index1 = 0;
int index2 = 0;
int len1 = op1.size();
int len2 = op2.size();
vector<pair< int , int > > 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<pair< int , int > > queryUtil(
vector<pair< int , int > > tree[],
int treeIndex, int start,
int end, int left, int right)
{ if (start > right || end < left) {
tree[0].clear();
return tree[0];
}
if (start >= left && end <= right) {
return tree[treeIndex];
}
int mid = (start + end) / 2;
vector<pair< int , int > > op1
= queryUtil(tree, 2 * treeIndex,
start, mid,
left, right);
vector<pair< int , int > > 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<pair< int , int > > tree[],
int treeIndex, int start,
int end, int left, int right)
{ vector<pair< int , int > > 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<pair< int , int > > 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[0]);
int queries = 2;
int Q[queries][2] = { { 2, 4 }, { 1, 5 } };
// Solve the queries
for ( int i = 0; i < queries; i++) {
solveQueries(arr, len, Q[i][0], Q[i][1]);
}
return 0;
} |
import java.util.ArrayList;
public class Main {
static final int MOD = 1000000007 ;
static final int MAXN = 1000001 ;
// Array to store the precomputed prime numbers
static int [] spf = new int [MAXN];
// Function to use Sieve to compute
// and store prime numbers
static void sieve()
{
spf[ 1 ] = 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
static ArrayList<Integer> getFactorization( int x)
{
ArrayList<Integer> ret = new ArrayList<>();
while (x != 1 ) {
ret.add(spf[x]);
x /= spf[x];
}
return ret;
}
// Function to merge the right and left tree
static void merge(ArrayList< int []>[] tree,
int treeIndex)
{
int index1 = 0 ;
int index2 = 0 ;
int len1 = tree[ 2 * treeIndex].size();
int len2 = tree[ 2 * treeIndex + 1 ].size();
ArrayList< int []> mergedAns = new ArrayList<>();
while (index1 < len1 && index2 < len2) {
if (tree[ 2 * treeIndex].get(index1)[ 0 ]
== tree[ 2 * treeIndex + 1 ].get(index2)[ 0 ]) {
int [] temp
= { tree[ 2 * treeIndex].get(index1)[ 0 ],
(tree[ 2 * treeIndex].get(index1)[ 1 ]
+ tree[ 2 * treeIndex + 1 ].get(
index2)[ 1 ])
% MOD };
mergedAns.add(temp);
index1++;
index2++;
}
else if (tree[ 2 * treeIndex].get(index1)[ 0 ]
< tree[ 2 * treeIndex + 1 ].get(
index2)[ 0 ]) {
mergedAns.add(
tree[ 2 * treeIndex].get(index1));
index1++;
}
else {
mergedAns.add(
tree[ 2 * treeIndex + 1 ].get(index2));
index2++;
}
}
while (index1 < len1) {
mergedAns.add(tree[ 2 * treeIndex].get(index1));
index1++;
}
while (index2 < len2) {
mergedAns.add(
tree[ 2 * treeIndex + 1 ].get(index2));
index2++;
}
tree[treeIndex] = mergedAns;
}
// Recursive function to build a segment tree
static void buildTree(ArrayList< int []>[] tree,
int treeIndex, int start, int end,
int [] arr)
{
if (start == end) {
int val = arr[start];
ArrayList<Integer> primeFac
= getFactorization(val);
for ( int it : primeFac) {
int power = 0 ;
while (val % it == 0 ) {
val = val / it;
power++;
}
int [] temp = { it, power };
tree[treeIndex].add(temp);
}
return ;
}
int mid = (start + end) / 2 ;
buildTree(tree, 2 * treeIndex, start, mid, arr);
buildTree(tree, 2 * treeIndex + 1 , mid + 1 , end,
arr);
merge(tree, treeIndex);
}
// Function to return the number of divisors
// of a product of an array from left to right
static int query(ArrayList< int []>[] tree, int treeIndex,
int start, int end, int left,
int right)
{
ArrayList< int []> res = queryUtil(
tree, treeIndex, start, end, left, right);
int sum = 1 ;
for ( int [] it : res) {
sum *= (it[ 1 ] + 1 );
sum %= MOD;
}
return sum;
}
// Function similar to merge() method
// But here it takes two vectors and
// returns a vector of the power of primes
static ArrayList< int []> mergeUtil(ArrayList< int []> op1,
ArrayList< int []> op2)
{
int index1 = 0 ;
int index2 = 0 ;
int len1 = op1.size();
int len2 = op2.size();
ArrayList< int []> mergedAns = new ArrayList<>();
while (index1 < len1 && index2 < len2) {
if (op1.get(index1)[ 0 ] == op2.get(index2)[ 0 ]) {
int [] temp = { op1.get(index1)[ 0 ],
(op1.get(index1)[ 1 ]
+ op2.get(index2)[ 1 ])
% MOD };
mergedAns.add(temp);
index1++;
index2++;
}
else if (op1.get(index1)[ 0 ]
< op2.get(index2)[ 0 ]) {
mergedAns.add(op1.get(index1));
index1++;
}
else {
mergedAns.add(op2.get(index2));
index2++;
}
}
while (index1 < len1) {
mergedAns.add(op1.get(index1));
index1++;
}
while (index2 < len2) {
mergedAns.add(op2.get(index2));
index2++;
}
return mergedAns;
}
// Function to merge the right
// and the left tree
static ArrayList< int []>
queryUtil(ArrayList< int []>[] tree, int treeIndex,
int start, int end, int left, int right)
{
if (left > end || right < start) {
return new ArrayList<>();
}
if (left <= start && end <= right) {
return tree[treeIndex];
}
int mid = (start + end) / 2 ;
ArrayList< int []> op1 = queryUtil(
tree, 2 * treeIndex, start, mid, left, right);
ArrayList< int []> op2
= queryUtil(tree, 2 * treeIndex + 1 , mid + 1 ,
end, left, right);
return mergeUtil(op1, op2);
}
// Function to solve queries
static void solveQueries( int [] arr, int len, int l,
int r)
{
int x = ( int )Math.ceil(Math.log(len) / Math.log( 2 ));
int max_size = 2 * ( int )Math.pow( 2 , x) - 1 ;
ArrayList< int []>[] tree = new ArrayList[max_size];
for ( int i = 0 ; i < tree.length; i++) {
tree[i] = new ArrayList<>();
}
buildTree(tree, 1 , 0 , len - 1 , arr);
System.out.println(
query(tree, 1 , 0 , len - 1 , l - 1 , r - 1 ));
}
public static void main(String[] args)
{
// Precomputing the prime numbers using sieve
sieve();
int [] arr = { 5 , 2 , 3 , 1 , 4 };
int len = arr.length;
int queries = 2 ;
int [][] Q = { { 2 , 4 }, { 1 , 5 } };
// Solve the queries
for ( int i = 0 ; i < queries; i++) {
solveQueries(arr, len, Q[i][ 0 ], Q[i][ 1 ]);
}
}
} |
from typing import List , Tuple
from math import ceil, log2, pow
import sys
sys.setrecursionlimit( 10000 )
MOD = 1000000007
MAXN = 1000001
# Array to store the precomputed prime numbers spf = [ 0 for _ in range (MAXN)]
# Function to use Sieve to compute # and store prime numbers def sieve() - > None :
spf[ 1 ] = 1
for i in range ( 2 , MAXN):
spf[i] = i
for i in range ( 4 , MAXN, 2 ):
spf[i] = 2
i = 3
while i * i < MAXN:
if (spf[i] = = i):
for j in range (i * i, MAXN, i):
if (spf[j] = = j):
spf[j] = i
i + = 1
# Function to find the # prime factors of a value def getFactorization(x: int ) - > List [ int ]:
# Vector to store the prime factors
ret = []
# For every prime factor of x,
# push it to the vector
while (x ! = 1 ):
ret.append(spf[x])
x = x / / spf[x]
# Return the prime factors
return ret
# Recursive function to build segment tree # by merging the power pf primes def buildTree(tree: List [ List [ Tuple [ int ]]], treeIndex: int ,
start: int , end: int , arr: List [ int ]) - > None :
# Base case
if (start = = end):
val = arr[start]
primeFac = getFactorization(val)
for it in primeFac:
power = 0
while (val % it = = 0 ):
val = val / / it
power + = 1
# Storing powers of prime
# in tree at treeIndex
tree[treeIndex].append((it, power))
return
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 def merge(tree: List [ List [ Tuple [ int ]]], treeIndex: int ) - > None :
index1 = 0
index2 = 0
len1 = len (tree[ 2 * treeIndex])
len2 = len (tree[ 2 * treeIndex + 1 ])
# Fill this array in such a way such that values
# of prime remain sorted similar to mergesort
while (index1 < len1 and index2 < len2):
# If both of the elements are same
if (tree[ 2 * treeIndex][index1][ 0 ] = =
tree[ 2 * treeIndex + 1 ][index2][ 0 ]):
tree[treeIndex].append((tree[ 2 * treeIndex][index1][ 0 ],
tree[ 2 * treeIndex][index1][ 1 ] +
tree[ 2 * treeIndex + 1 ][index2][ 1 ]))
index1 + = 1
index2 + = 1
# If the element on the left part
# is greater than the right part
elif (tree[ 2 * treeIndex][index1][ 0 ] >
tree[ 2 * treeIndex + 1 ][index2][ 0 ]):
tree[treeIndex].append((tree[ 2 * treeIndex + 1 ][index2][ 0 ],
tree[ 2 * treeIndex + 1 ][index2][ 1 ]))
index2 + = 1
# If the element on the left part
# is less than the right part
else :
tree[treeIndex].append((tree[ 2 * treeIndex][index1][ 0 ],
tree[ 2 * treeIndex][index1][ 1 ]))
index1 + = 1
# Insert the leftover elements
# from the left part
while (index1 < len1):
tree[treeIndex].append(
(tree[ 2 * treeIndex][index1][ 0 ],
tree[ 2 * treeIndex][index1][ 1 ]))
index1 + = 1
# Insert the leftover elements
# from the right part
while (index2 < len2):
tree[treeIndex].append((tree[ 2 * treeIndex + 1 ][index2][ 0 ],
tree[ 2 * treeIndex + 1 ][index2][ 1 ]))
index2 + = 1
return
# Function similar to merge() method # But here it takes two vectors and # return a vector of power of primes def mergeUtil(op1: List [ Tuple [ int ]],
op2: List [ Tuple [ int ]]) - > List [ Tuple [ int ]]:
index1 = 0
index2 = 0
len1 = len (op1)
len2 = len (op2)
res = []
while (index1 < len1 and index2 < len2):
if (op1[index1][ 0 ] = = op2[index2][ 0 ]):
res.append((op1[index1][ 0 ],
(op1[index1][ 1 ] +
op2[index2][ 1 ])))
index1 + = 1
index2 + = 1
elif (op1[index1][ 0 ] > op2[index2][ 0 ]):
res.append((op2[index2][ 0 ], op2[index2][ 1 ]))
index2 + = 1
else :
res.append((op1[index1][ 0 ], op1[index1][ 1 ]))
index1 + = 1
while (index1 < len1):
res.append((op1[index1][ 0 ], op1[index1][ 1 ]))
index1 + = 1
while (index2 < len2):
res.append((op2[index2][ 0 ], op2[index2][ 1 ]))
index2 + = 1
return res
# Function similar to query() method # as in segment tree # Here also the result is merged def queryUtil(tree: List [ List [ Tuple [ int ]]], treeIndex: int ,
start: int ,end: int , left: int ,
right: int ) - > List [ Tuple [ int ]]:
if (start > right or end < left):
tree[ 0 ].clear()
return tree[ 0 ]
if (start > = left and end < = right):
return tree[treeIndex]
mid = (start + end) / / 2
op1 = queryUtil(tree, 2 * treeIndex, start,
mid, left, right)
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 def query(tree: List [ List [ Tuple [ int ]]], treeIndex: int ,
start: int , end: int , left: int , right: int ) - > int :
res = queryUtil(tree, treeIndex, start, end, left, right)
sum = 1
for it in res:
sum * = (it[ 1 ] + 1 )
sum % = MOD
return sum
# Function to solve queries def solveQueries(arr: List [ int ], length: int ,
l: int , r: int ) - > None :
# Calculate the size of segment tree
x = int (ceil(log2(length)))
# Maximum size of segment tree
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
tree = [[] for _ in range (max_size)]
# building the tree
buildTree(tree, 1 , 0 , length - 1 , arr)
# Find the required number of divisors
# of product of array from l to r
print (query(tree, 1 , 0 , length - 1 , l - 1 , r - 1 ))
# Driver code if __name__ = = "__main__" :
# Precomputing the prime numbers using sieve
sieve()
arr = [ 5 , 2 , 3 , 1 , 4 ]
length = len (arr)
queries = 2
Q = [ [ 2 , 4 ], [ 1 , 5 ] ]
# Solve the queries
for i in range (queries):
solveQueries(arr, length, Q[i][ 0 ], Q[i][ 1 ])
# This code is contributed by sanjeev2552 |
using System;
using System.Collections.Generic;
class GFG {
// Constants for maximum array size and MOD value
const int MAXN = 1000001;
const int MOD = 1000000007;
// Array to store the precomputed prime numbers
static int [] spf = new int [MAXN];
// Function to use Sieve to compute
// and store prime numbers
static void Sieve()
{
spf[1] = 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
static List< int > GetFactorization( int x)
{
List< int > ret = new List< int >();
while (x != 1) {
ret.Add(spf[x]);
x = x / spf[x];
}
return ret;
}
// Recursive function to build segment tree by merging
// the power of primes
static void BuildTree(List<Tuple< int , int > >[] tree,
int treeIndex, int start, int end,
int [] arr)
{
if (start == end) {
int val = arr[start];
List< int > primeFac = GetFactorization(val);
foreach ( int it in primeFac)
{
int power = 0;
while (val % it == 0) {
val = val / it;
power++;
}
tree[treeIndex].Add(
Tuple.Create(it, power));
}
return ;
}
int mid = (start + end) / 2;
BuildTree(tree, 2 * treeIndex, start, mid, arr);
BuildTree(tree, 2 * treeIndex + 1, mid + 1, end,
arr);
Merge(tree, treeIndex);
}
// Function to merge the right and the left tree
static void Merge(List<Tuple< int , int > >[] tree,
int treeIndex)
{
int index1 = 0;
int index2 = 0;
int len1 = tree[2 * treeIndex].Count;
int len2 = tree[2 * treeIndex + 1].Count;
List<Tuple< int , int > > merged
= new List<Tuple< int , int > >();
while (index1 < len1 && index2 < len2) {
if (tree[2 * treeIndex][index1].Item1
== tree[2 * treeIndex + 1][index2].Item1) {
merged.Add(Tuple.Create(
tree[2 * treeIndex][index1].Item1,
tree[2 * treeIndex][index1].Item2
+ tree[2 * treeIndex + 1][index2]
.Item2));
index1++;
index2++;
}
else if (tree[2 * treeIndex][index1].Item1
> tree[2 * treeIndex + 1][index2]
.Item1) {
merged.Add(Tuple.Create(
tree[2 * treeIndex + 1][index2].Item1,
tree[2 * treeIndex + 1][index2].Item2));
index2++;
}
else {
merged.Add(Tuple.Create(
tree[2 * treeIndex][index1].Item1,
tree[2 * treeIndex][index1].Item2));
index1++;
}
}
while (index1 < len1) {
merged.Add(Tuple.Create(
tree[2 * treeIndex][index1].Item1,
tree[2 * treeIndex][index1].Item2));
index1++;
}
while (index2 < len2) {
merged.Add(Tuple.Create(
tree[2 * treeIndex + 1][index2].Item1,
tree[2 * treeIndex + 1][index2].Item2));
index2++;
}
tree[treeIndex] = merged;
}
// Function to return the number of divisors of product
// of array from left to right
static int Query(List<Tuple< int , int > >[] tree,
int treeIndex, int start, int end,
int left, int right)
{
List<Tuple< int , int > > result = QueryUtil(
tree, treeIndex, start, end, left, right);
int sum = 1;
foreach (Tuple< int , int > it in result)
{
sum *= (it.Item2 + 1);
sum %= MOD;
}
return sum;
}
// Function similar to query() method as in the segment
// tree
static List<Tuple< int , int > >
QueryUtil(List<Tuple< int , int > >[] tree, int treeIndex,
int start, int end, int left, int right)
{
if (start > right || end < left) {
tree[0].Clear();
return tree[0];
}
if (start >= left && end <= right) {
return tree[treeIndex];
}
int mid = (start + end) / 2;
List<Tuple< int , int > > op1 = QueryUtil(
tree, 2 * treeIndex, start, mid, left, right);
List<Tuple< int , int > > op2
= QueryUtil(tree, 2 * treeIndex + 1, mid + 1,
end, left, right);
return MergeUtil(op1, op2);
}
// Function similar to merge() method but here it takes
// two lists and returns a list of power of primes
static List<Tuple< int , int > >
MergeUtil(List<Tuple< int , int > > op1,
List<Tuple< int , int > > op2)
{
int index1 = 0;
int index2 = 0;
int len1 = op1.Count;
int len2 = op2.Count;
List<Tuple< int , int > > res
= new List<Tuple< int , int > >();
while (index1 < len1 && index2 < len2) {
if (op1[index1].Item1 == op2[index2].Item1) {
res.Add(Tuple.Create(
op1[index1].Item1,
op1[index1].Item2 + op2[index2].Item2));
index1++;
index2++;
}
else if (op1[index1].Item1
> op2[index2].Item1) {
res.Add(Tuple.Create(op2[index2].Item1,
op2[index2].Item2));
index2++;
}
else {
res.Add(Tuple.Create(op1[index1].Item1,
op1[index1].Item2));
index1++;
}
}
while (index1 < len1) {
res.Add(Tuple.Create(op1[index1].Item1,
op1[index1].Item2));
index1++;
}
while (index2 < len2) {
res.Add(Tuple.Create(op2[index2].Item1,
op2[index2].Item2));
index2++;
}
return res;
}
// Function to solve queries
static void SolveQueries( int [] arr, int len, int left,
int right)
{
int x = ( int )Math.Ceiling(Math.Log(len, 2));
int max_size = 2 * ( int )Math.Pow(2, x) - 1;
List<Tuple< int , int > >[] tree
= new List<Tuple< int , int > >[ max_size ];
for ( int i = 0; i < max_size; i++) {
tree[i] = new List<Tuple< int , int > >();
}
BuildTree(tree, 1, 0, len - 1, arr);
Console.WriteLine(Query(tree, 1, 0, len - 1,
left - 1, right - 1));
}
// Driver code
static void Main()
{
// Precomputing the prime numbers using sieve
Sieve();
int [] arr = { 5, 2, 3, 1, 4 };
int len = arr.Length;
int queries = 2;
int [, ] Q = { { 2, 4 }, { 1, 5 } };
for ( int i = 0; i < queries; i++) {
SolveQueries(arr, len, Q[i, 0], Q[i, 1]);
}
}
} |
<script>
//JavaScript code for the above approach
const MOD = 1000000007;
const MAXN = 1000001;
let spf = new Array(MAXN);
function merge(tree, treeIndex) {
let index1 = 0;
let index2 = 0;
let len1 = tree[2 * treeIndex].length;
let len2 = tree[2 * treeIndex + 1].length;
while (index1 < len1 && index2 < len2) {
if (tree[2 * treeIndex][index1][0] === tree[2 * treeIndex + 1][index2][0]) {
tree[treeIndex].push([tree[2 * treeIndex][index1][0],
(tree[2 * treeIndex][index1][1] + tree[2 * treeIndex + 1][index2][1]) % MOD,
]);
index1++;
index2++;
}
else if (tree[2 * treeIndex][index1][0] < tree[2 * treeIndex + 1][index2][0]) {
tree[treeIndex].push(tree[2 * treeIndex][index1]);
index1++;
}
else {
tree[treeIndex].push(tree[2 * treeIndex + 1][index2]);
index2++;
}
}
while (index1 < len1) {
tree[treeIndex].push(tree[2 * treeIndex][index1]);
index1++;
}
while (index2 < len2) {
tree[treeIndex].push(tree[2 * treeIndex + 1][index2]);
index2++;
}
}
function sieve() {
spf[1] = 1;
for (let i = 2; i < MAXN; i++) {
spf[i] = i;
}
for (let i = 4; i < MAXN; i += 2) {
spf[i] = 2;
}
for (let i = 3; i * i < MAXN; i++) {
if (spf[i] === i) {
for (let j = i * i; j < MAXN; j += i) {
if (spf[j] === j) {
spf[j] = i;
}
}
}
}
}
function getFactorization(x) {
let ret = [];
while (x !== 1) {
ret.push(spf[x]);
x = Math.floor(x / spf[x]);
}
return ret;
}
function buildTree(tree, treeIndex, start, end, arr) {
if (start === end) {
let val = arr[start];
let primeFac = getFactorization(val);
for (let it of primeFac) {
let power = 0;
while (val % it === 0) {
val = Math.floor(val / it);
power++;
}
tree[treeIndex].push([it, power]);
}
return ;
}
let mid = Math.floor((start + end) / 2);
buildTree(tree, 2 * treeIndex, start, mid, arr);
buildTree(tree, 2 * treeIndex + 1, mid + 1, end, arr);
merge(tree, treeIndex);
return ;
}
function query(tree, treeIndex, start, end, left, right) {
if (left > end || right < start) {
return [];
}
if (left <= start && end <= right) {
return tree[treeIndex];
}
let mid = Math.floor((start + end) / 2);
let op1 = query(tree, 2 * treeIndex, start, mid, left, right);
let op2 = query(tree, 2 * treeIndex + 1, mid + 1, end, left, right);
return mergeUtil(op1, op2);
}
function mergeUtil(op1, op2) {
let index1 = 0;
let index2 = 0;
let len1 = op1.length;
let len2 = op2.length;
let mergedAns = [];
while (index1 < len1 && index2 < len2) {
if (op1[index1][0] === op2[index2][0]) {
mergedAns.push([
op1[index1][0],
(op1[index1][1] + op2[index2][1]) % MOD,
]);
index1++;
index2++;
}
else if (op1[index1][0] < op2[index2][0]) {
mergedAns.push(op1[index1]);
index1++;
}
else {
mergedAns.push(op2[index2]);
index2++;
}
}
while (index1 < len1) {
mergedAns.push(op1[index1]);
index1++;
}
while (index2 < len2) {
mergedAns.push(op2[index2]);
index2++;
}
return mergedAns;
}
function queryUtil(tree, treeIndex, start, end, left, right) {
if (left > end || right < start) {
return [];
}
if (left <= start && end <= right) {
return tree[treeIndex];
}
let mid = Math.floor((start + end) / 2);
let op1 = queryUtil(tree, 2 * treeIndex, start, mid, left, right);
let op2 = queryUtil(tree, 2 * treeIndex + 1, mid + 1, end, left, right);
return mergeUtil(op1, op2);
}
function query(tree, treeIndex, start, end, left, right) {
let res = queryUtil(tree, treeIndex, start, end, left, right);
let sum = 1;
for (let it of res) {
sum *= (it[1] + 1);
sum %= MOD;
}
return sum;
}
function solveQueries(arr, len, l, r) {
let x = Math.ceil(Math.log2(len));
let max_size = 2 * Math.pow(2, x) - 1;
let tree = new Array(max_size);
for (let i = 0; i < tree.length; i++) {
tree[i] = [];
}
buildTree(tree, 1, 0, len - 1, arr);
document.write(query(tree, 1, 0, len - 1, l - 1, r - 1)+ "<br>" );
}
sieve();
let arr = [5, 2, 3, 1, 4];
let len = arr.length;
let queries = 2;
let Q = [[2, 4],
[1, 5],
];
for (let i = 0; i < queries; i++) {
solveQueries(arr, len, Q[i][0], Q[i][1]);
}
// This code is contributed by Potta Lokesh
</script> |
4 16
Time Complexity: Q * (log (N))
Space complexity: O(MAXN+N*log(N))