Skip to content
Related Articles

Related Articles

Improve Article
Queries to calculate sum of array elements consisting of odd number of divisors
  • Last Updated : 06 May, 2021

Given an array arr[] consisting of N positive integers and an array Query[][2] consisting of Q queries of the form {L, R}, the task is to find the sum of all array elements from the range [L, R], having odd number of divisors.

Examples:

Input: arr[] = {2, 4, 5, 6, 9}, Q = 3, Query[][] = {{0, 2}, {1, 3}, {1, 4}} 
Output: 4 4 13 
Explanation: 
Query 1: Elements from indices [0, 2] are {2, 4, 5}. Out of them, only 4 has odd number of divisors. Therefore, the sum is 4.
Query 2: Elements from indices [1, 3] are {4, 5, 6}. Out of them, only 4 has odd number of divisors. Therefore, the sum is 4.
Query 3: Elements from the indices [1, 4] are {4, 5, 6, 9}. Out of them, only 4, 9 has odd number of divisors. Therefore, the sum is 13.

Input: arr[] = {1, 16, 5, 4, 9}, Q = 2, Query[][] = {{1, 3}, {0, 2}} 
Output: 20 17 

Naive Approach: The simplest approach is to solve the given problem is to traverse the given array arr[] over the range [L, R] for each query and find the sum of elements in the range [L, R] having odd numbers of divisors, and print the resultant sum.

Time Complexity: O(Q * N *√N) 
Auxiliary Space: O(1)

Efficient Approach: The above approach can also be optimized which is based on the below observation:

Follow the steps below to solve the problem:



Below is the implementation of the above approach: 

C++




// C++ program for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to get the middle index
// from the given ranges
int getMid(int s, int e)
{
    return s + (e - s) / 2;
}
 
// Recursive function to find 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 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 find the sum of elements
// in the range from index qs (query
// start) to qe (query end)
int getSum(int* st, int n, int qs, int qe)
{
    // Invalid ranges
    if (qs < 0 || qe > n - 1 || qs > qe) {
        cout << "Invalid Input";
        return -1;
    }
 
    return getSumUtil(st, 0, n - 1, qs, qe, 0);
}
 
// Recursive function to construct the
// Segment Tree for array[ss..se]. si
// is index of current node in tree st
int constructSTUtil(int arr[], int ss,
                    int se, int* st,
                    int si)
{
    // If there is one element
    // in the array
    if (ss == se) {
        st[si] = arr[ss];
        return arr[ss];
    }
 
    int mid = getMid(ss, se);
 
    // Recur for left and right
    // subtrees and store the sum
    // of values in this node
    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 the 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;
}
 
// Function to find the sum of elements
// having odd number of divisors in
// index range [L, R] for Q queries
void OddDivisorsSum(int n, int q, int arr[],
                    vector<pair<int, int> > Query)
{
    // Traverse the array, arr[]
    for (int i = 0; i < n; i++) {
        int sq = sqrt(arr[i]);
 
        // Replace elements that are
        // not perfect squares with 0
        if (sq * sq != arr[i])
            arr[i] = 0;
    }
 
    // Build segment tree from the
    // given array
    int* st = constructST(arr, n);
 
    // Iterate through all the queries
    for (int i = 0; i < q; i++) {
        int l = Query[i].first;
        int r = Query[i].second;
 
        // Print sum of values in
        // array from index l to r
        cout << getSum(st, n, l, r) << " ";
    }
}
 
// Driver Code
int main()
{
    int arr[] = { 2, 4, 5, 6, 9 };
    int N = sizeof(arr) / sizeof(arr[0]);
    int Q = 3;
    vector<pair<int, int> > Query
        = { { 0, 2 }, { 1, 3 }, { 1, 4 } };
    OddDivisorsSum(N, Q, arr, Query);
 
    return 0;
}

Java




// java program for the above approach
import java.io.*;
import java.lang.*;
import java.util.*;
 
public class GFG {
 
    // Function to get the middle index
    // from the given ranges
    static int getMid(int s, int e)
    {
        return s + (e - s) / 2;
    }
 
    // Recursive function to find the sum
    // of values in the given range of
    // the array
    static 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 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 find the sum of elements
    // in the range from index qs (query
    // start) to qe (query end)
    static int getSum(int st[], int n, int qs, int qe)
    {
        // Invalid ranges
        if (qs < 0 || qe > n - 1 || qs > qe) {
            System.out.println("Invalid Input");
            return -1;
        }
 
        return getSumUtil(st, 0, n - 1, qs, qe, 0);
    }
 
    // Recursive function to construct the
    // Segment Tree for array[ss..se]. si
    // is index of current node in tree st
    static int constructSTUtil(int arr[], int ss, int se,
                               int st[], int si)
    {
        // If there is one element
        // in the array
        if (ss == se) {
            st[si] = arr[ss];
            return arr[ss];
        }
 
        int mid = getMid(ss, se);
 
        // Recur for left and right
        // subtrees and store the sum
        // of values in this node
        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 the given array
    static int[] constructST(int arr[], int n)
    {
        // Allocate memory for the segment
        // tree 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;
 
        // 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;
    }
 
    // Function to find the sum of elements
    // having odd number of divisors in
    // index range [L, R] for Q queries
    static void OddDivisorsSum(int n, int q, int arr[],
                               int Query[][])
    {
        // Traverse the array, arr[]
        for (int i = 0; i < n; i++) {
            int sq = (int)Math.sqrt(arr[i]);
 
            // Replace elements that are
            // not perfect squares with 0
            if (sq * sq != arr[i])
                arr[i] = 0;
        }
 
        // Build segment tree from the
        // given array
        int st[] = constructST(arr, n);
 
        // Iterate through all the queries
        for (int i = 0; i < q; i++) {
            int l = Query[i][0];
            int r = Query[i][1];
 
            // Print sum of values in
            // array from index l to r
            System.out.print(getSum(st, n, l, r) + " ");
        }
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        int arr[] = { 2, 4, 5, 6, 9 };
        int N = arr.length;
        int Q = 3;
        int Query[][] = { { 0, 2 }, { 1, 3 }, { 1, 4 } };
        OddDivisorsSum(N, Q, arr, Query);
    }
}
 
// This code is contributed by Kingash.
Output: 
4 4 13

 

Time Complexity: O(Q * log(N))
Auxiliary Space: O(N)

Efficient Approach: To optimize the above approach, the idea is to use an auxiliary array that stores the prefix sum of elements having an odd number of divisors. Follow the steps below to solve the problem: 

Below is the implementation of the above approach: 

C++




// C++ program for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the sum of elements
// having odd number of divisors in
// index range [L, R] for Q queries
void OddDivisorsSum(int n, int q, int a[],
                    vector<pair<int, int> > Query)
{
    // Initialize the dp[] array
    int DP[n] = { 0 };
 
    // Traverse the array, arr[]
    for (int i = 0; i < n; i++) {
        int x = sqrt(a[i]);
 
        // If a[i] is a perfect square,
        // then update value of DP[i] to a[i]
        if (x * x == a[i])
            DP[i] = a[i];
    }
 
    // Find the prefix sum of DP[] array
    for (int i = 1; i < n; i++) {
        DP[i] = DP[i - 1] + DP[i];
    }
 
    // Iterate through all the queries
    for (int i = 0; i < q; i++) {
 
        int l = Query[i].first;
        int r = Query[i].second;
 
        // Find the sum for each query
        if (l == 0) {
            cout << DP[r] << " ";
        }
        else {
            cout << DP[r] - DP[l - 1]
                 << " ";
        }
    }
}
 
// Driver Code
int main()
{
    int arr[] = { 2, 4, 5, 6, 9 };
    int N = sizeof(arr) / sizeof(arr[0]);
    int Q = 3;
    vector<pair<int, int> > Query
        = { { 0, 2 }, { 1, 3 }, { 1, 4 } };
    OddDivisorsSum(N, Q, arr, Query);
 
    return 0;
}

Python3




# Python3 program for the above approach
from math import sqrt
 
# Function to find the sum of elements
# having odd number of divisors in
# index range [L, R] for Q queries
def OddDivisorsSum(n, q, a, Query):
   
    # Initialize the dp[] array
    DP = [0]*n
     
    # Traverse the array, arr[]
    for i in range(n):
        x = sqrt(a[i])
 
        # If a[i] is a perfect square,
        # then update value of DP[i] to a[i]
        if (x * x == a[i]):
            DP[i] = a[i]
 
    # Find the prefix sum of DP[] array
    for i in range(1, n):
        DP[i] = DP[i - 1] + DP[i]
 
    # Iterate through all the queries
    for i in range(q):
        l = Query[i][0]
        r = Query[i][1]
 
        # Find the sum for each query
        if (l == 0):
            print(DP[r], end=" ")
        else:
            print(DP[r] - DP[l - 1], end=" ")
 
# Driver Code
if __name__ == '__main__':
    arr = [2, 4, 5, 6, 9]
    N = len(arr)
    Q = 3
    Query = [ [ 0, 2 ], [ 1, 3 ], [ 1, 4 ] ]
    OddDivisorsSum(N, Q, arr, Query)
 
    # This code is contributed by mohit kumar 29.

C#




// C# program for the above approach
using System;
class GFG
{
   
    // Function to find the sum of elements
    // having odd number of divisors in
    // index range [L, R] for Q queries
    static void OddDivisorsSum(int n, int q, int[] a,
                               int[, ] Query)
    {
       
        // Initialize the dp[] array
        int[] DP = new int[n];
 
        // Traverse the array, arr[]
        for (int i = 0; i < n; i++) {
            int x = (int)(Math.Sqrt(a[i]));
 
            // If a[i] is a perfect square,
            // then update value of DP[i] to a[i]
            if (x * x == a[i])
                DP[i] = a[i];
        }
 
        // Find the prefix sum of DP[] array
        for (int i = 1; i < n; i++) {
            DP[i] = DP[i - 1] + DP[i];
        }
 
        // Iterate through all the queries
        for (int i = 0; i < q; i++) {
 
            int l = Query[i, 0];
            int r = Query[i, 1];
 
            // Find the sum for each query
            if (l == 0) {
                Console.Write(DP[r] + " ");
            }
            else {
                Console.Write(DP[r] - DP[l - 1] + " ");
            }
        }
    }
 
    // Driver Code
    public static void Main()
    {
        int[] arr = { 2, 4, 5, 6, 9 };
        int N = arr.Length;
        int Q = 3;
        int[, ] Query = { { 0, 2 }, { 1, 3 }, { 1, 4 } };
        OddDivisorsSum(N, Q, arr, Query);
    }
}
 
// This code is contributed by ukasp.
Output: 
4 4 13

 

Time complexity: O(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.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with industry experts, please refer Geeks Classes Live 




My Personal Notes arrow_drop_up
Recommended Articles
Page :