Open In App

Sum of Interval and Update with Number of Divisors

Last Updated : 20 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array A of N integers. You have to answer two types of queries : 1. Update [l, r] – for every i in range from l to r update Ai with D(Ai), where D(Ai) represents the number of divisors of Ai 2. Query [l, r] – calculate the sum of all numbers ranging between l and r in array A. Input is given as two integers N and Q, representing number of integers in array and number of queries respectively. Next line contains an array of n integers followed by Q queries where ith query is represented as typei, li, ri

Prerequisite : Binary Indexed Trees | Segment Trees Examples :

Input : 7 4
        6 4 1 10 3 2 4
        2 1 7
        2 4 5
        1 3 5
        2 4 4
Output : 30
         13
         4
Explanation : First query is to calculate the sum of numbers from A1 to A7 which is 6 + 4
+ 1 + 10 + 3 + 2 + 4 = 30. Similarly, second query results into 13. For third query, 
which is update operation, hence A3 will remain 1, A4 will become 4 and A5 will become 2.
Fourth query will result into A4 = 4. 

Naive Approach: A simple solution is to run a loop from l to r and calculate sum of elements in given range. To update a value, precompute the values of number of divisors of every number and simply do arr[i] = divisors[arr[i]]. 

Efficient Approach : 

The idea is to reduce the time complexity for each query and update operation to O(logN). Use Binary Indexed Trees (BIT) or Segment Trees. Construct a BIT[] array and have two functions for query and update operation and precompute the number of divisors for each number. 

Now, for each update operation, the key observation is that the numbers ‘1’ and ‘2’ will have ‘1’ and ‘2’ as their number of divisors respectively, so if it exists in the range of update query, they don’t need to be updated. We will use a set to store the index of only those numbers which are greater than 2 and use binary search to find the l index of the update query and increment the l index until every element is updated in range of that update query.

If the arr[i] has only 2 divisors then after updating it, remove it from the set as it will always be 2 even after any next update query. For sum query operation, simply do query(r) – query(l – 1). 

Implementation:

C++




// CPP program to calculate sum
// in an interval and update with
// number of divisors
#include <bits/stdc++.h>
using namespace std;
 
int divisors[100], BIT[100];
 
// structure for queries with members type,
// leftIndex, rightIndex of the query
struct queries
{
    int type, l, r;
};
 
// function to calculate the number
// of divisors of each number
void calcDivisors()
{
    for (int i = 1; i < 100; i++) {
        for (int j = i; j < 100; j += i) {
            divisors[j]++;
        }
    }
}
 
// function for updating the value
void update(int x, int val, int n)
{
    for (x; x <= n; x += x&-x) {
        BIT[x] += val;
    }
}
 
// function for calculating the required
// sum between two indexes
int sum(int x)
{
    int s = 0;
    for (x; x > 0; x -= x&-x) {
        s += BIT[x];
    }
    return s;
}
 
// function to return answer to queries
void answerQueries(int arr[], queries que[], int n, int q)
{
    // Declaring a Set
    set<int> s;
    for (int i = 1; i < n; i++) {
         
        // inserting indexes of those numbers
        // which are greater than 2
        if(arr[i] > 2) s.insert(i);
        update(i, arr[i], n);
    }
     
    for (int i = 0; i < q; i++) {
         
        // update query
        if (que[i].type == 1) {
            while (true) {
                 
                // find the left index of query in
                // the set using binary search
                auto it = s.lower_bound(que[i].l);
                 
                // if it crosses the right index of
                // query or end of set, then break
                if(it == s.end() || *it > que[i].r) break;
                 
                que[i].l = *it;
                 
                // update the value of arr[i] to
                // its number of divisors
                update(*it, divisors[arr[*it]] - arr[*it], n);
                 
                arr[*it] = divisors[arr[*it]];
                 
                // if updated value becomes less than or
                // equal to 2 remove it from the set
                if(arr[*it] <= 2) s.erase(*it);
                 
                // increment the index
                que[i].l++;
            }
        }
         
        // sum query
        else {
            cout << (sum(que[i].r) - sum(que[i].l - 1)) << endl;
        }
    }
}
 
// Driver Code
int main()
{
    // precompute the number of divisors for each number
    calcDivisors();
     
    int q = 4;
     
    // input array
    int arr[] = {0, 6, 4, 1, 10, 3, 2, 4};
    int n = sizeof(arr) / sizeof(arr[0]);
     
    // declaring array of structure of type queries
    queries que[q + 1];
     
    que[0].type = 2, que[0].l = 1, que[0].r = 7;
    que[1].type = 2, que[1].l = 4, que[1].r = 5;
    que[2].type = 1, que[2].l = 3, que[2].r = 5;
    que[3].type = 2, que[3].l = 4, que[3].r = 4;
     
    // answer the Queries
    answerQueries(arr, que, n, q);
     
    return 0;
}


Java




import java.util.*;
 
public class Main {
 
    static int[] divisors = new int[100];
    static int[] BIT = new int[100];
    // structure for queries with members type,
    // leftIndex, rightIndex of the query
    static class Query {
        int type, l, r;
 
        public Query(int type, int l, int r)
        {
            this.type = type;
            this.l = l;
            this.r = r;
        }
    }
    // function to calculate the number
    // of divisors of each number
    static void calcDivisors()
    {
        for (int i = 1; i < 100; i++) {
            for (int j = i; j < 100; j += i) {
                divisors[j]++;
            }
        }
    }
    // function for updating the value
 
    static void update(int x, int val, int n)
    {
        for (int i = x; i <= n; i += i & -i) {
            BIT[i] += val;
        }
    }
    // function for calculating the required
    // sum between two indexes
    static int sum(int x)
    {
        int s = 0;
        for (int i = x; i > 0; i -= i & -i) {
            s += BIT[i];
        }
        return s;
    }
    // function to return answer to queries
 
    static void answerQueries(int[] arr, Query[] que, int n,
                              int q)
    {
        // Declaring a Set
        Set<Integer> s = new TreeSet<>();
        for (int i = 1; i < n; i++) {
            // inserting indexes of those numbers
            // which are greater than 2
            if (arr[i] > 2)
                s.add(i);
            update(i, arr[i], n);
        }
 
        for (int i = 0; i < q; i++) {
            // update query
            if (que[i].type == 1) {
                while (true) {
                    // find the left index of query in
                    // the set using binary search
                    Iterator<Integer> it = s.iterator();
                    int idx = 0;
                    while (it.hasNext()) {
                        idx = it.next();
                        if (idx >= que[i].l
                            && idx <= que[i].r)
                            break;
                    }
                    if (idx > que[i].r)
                        break;
                    que[i].l = idx;
                    // update the value of arr[i] to
                    // its number of divisors
                    update(idx,
                           divisors[arr[idx]] - arr[idx],
                           n);
                    arr[idx] = divisors[arr[idx]];
                    // if updated value becomes less than or
                    // equal to 2 remove it from the set
                    if (arr[idx] <= 2)
                        s.remove(idx);
                    que[i].l++;
                }
            }
            // sum query
            else {
                System.out.println(sum(que[i].r)
                                   - sum(que[i].l - 1));
            }
        }
    }
 
      // Driver's code
    public static void main(String[] args)
    {
        calcDivisors();
        int q = 4;
        int[] arr = { 0, 6, 4, 1, 10, 3, 2, 4 };
        int n = arr.length;
        // declaring array of structure of type queries
        Query[] que = new Query[q + 1];
        que[0] = new Query(2, 1, 7);
        que[1] = new Query(2, 4, 5);
        que[2] = new Query(1, 3, 5);
        que[3] = new Query(2, 4, 4);
        answerQueries(arr, que, n, q);
    }
}


Python3




# Python code for the above approach
# function to calculate the number
# of divisors of each number
def calcDivisors():
    divisors = [0]*100
    for i in range(1, 100):
        for j in range(i, 100, i):
            divisors[j] += 1
    return divisors
 
# function for updating the value
def update(x, val, n, BIT):
    while x <= n:
        BIT[x] += val
        x += (x & -x)
 
# function for calculating the required
# sum between two indexes
def sum(x, BIT):
    s = 0
    while x > 0:
        s += BIT[x]
        x -= (x & -x)
    return s
 
# function to return answer to queries
def answerQueries(arr, que, n, q):
   
    # Declaring a Set
    s = set()
    BIT = [0] * (n + 1)
    divisors = calcDivisors()
    for i in range(1, n):
       
        # inserting indexes of those numbers
        # which are greater than 2
        if arr[i] > 2:
            s.add(i)
        update(i, arr[i], n, BIT)
    for i in range(q):
        # update query
        if que[i][0] == 1:
            leftIndex = que[i][1]
            rightIndex = que[i][2]
            for it in set(s):
                if it >= leftIndex and it <= rightIndex:
                    # update the value of arr[i] to
                    update(it, divisors[arr[it]] - arr[it], n, BIT)
                    arr[it] = divisors[arr[it]]
                    if arr[it] <= 2:
                        s.remove(it)
        # sum query
        else:
            print(sum(que[i][2], BIT) - sum(que[i][1] - 1, BIT))
 
# Driver Code
if __name__ == '__main__':
   
    # precompute the number of divisors for each number
    # input array
    arr = [0, 6, 4, 1, 10, 3, 2, 4]
    n = len(arr)
     
    # declaring array of structure of type queries
    que = [(2, 1, 7), (2, 4, 5), (1, 3, 5), (2, 4, 4)]
     
    # answer the Queries
    answerQueries(arr, que, n, len(que))
 
    # This code is contributed by lokeshpotta20


C#




// C# program for the above approach
using System;
using System.Collections.Generic;
 
public class GFG
{
  static int[] divisors = new int[100];
  static int[] BIT = new int[100];
 
  // structure for queries with members type,
  // leftIndex, rightIndex of the query
  public class Query
  {
    public int type, l, r;
 
    public Query(int type, int l, int r)
    {
      this.type = type;
      this.l = l;
      this.r = r;
    }
  }
 
  // function to calculate the number
  // of divisors of each number
  static void CalcDivisors()
  {
    for (int i = 1; i < 100; i++)
    {
      for (int j = i; j < 100; j += i)
      {
        divisors[j]++;
      }
    }
  }
 
  // function for updating the value
  static void Update(int x, int val, int n)
  {
    for (int i = x; i <= n; i += i & -i)
    {
      BIT[i] += val;
    }
  }
 
  // function for calculating the required
  // sum between two indexes
  static int Sum(int x)
  {
    int s = 0;
    for (int i = x; i > 0; i -= i & -i)
    {
      s += BIT[i];
    }
    return s;
  }
 
  // function to return answer to queries
  static void AnswerQueries(int[] arr, Query[] que, int n, int q)
  {
    // Declaring a Set
    SortedSet<int> s = new SortedSet<int>();
    for (int i = 1; i < n; i++)
    {
      // inserting indexes of those numbers
      // which are greater than 2
      if (arr[i] > 2)
        s.Add(i);
      Update(i, arr[i], n);
    }
 
    for (int i = 0; i < q; i++)
    {
      // update query
      if (que[i].type == 1)
      {
        while (true)
        {
          // find the left index of query in
          // the set using binary search
          var it = s.GetEnumerator();
          int idx = 0;
          while (it.MoveNext())
          {
            idx = it.Current;
            if (idx >= que[i].l
                && idx <= que[i].r)
              break;
          }
          if (idx > que[i].r)
            break;
          que[i].l = idx;
          // update the value of arr[i] to
          // its number of divisors
          Update(idx,
                 divisors[arr[idx]] - arr[idx],
                 n);
          arr[idx] = divisors[arr[idx]];
          // if updated value becomes less than or
          // equal to 2 remove it from the set
          if (arr[idx] <= 2)
            s.Remove(idx);
          que[i].l++;
        }
      }
      // sum query
      else
      {
        Console.WriteLine(Sum(que[i].r)
                          - Sum(que[i].l - 1));
      }
    }
  }
 
  // Driver's code
  public static void Main(string[] args)
  {
    CalcDivisors();
    int q = 4;
    int[] arr = { 0, 6, 4, 1, 10, 3, 2, 4 };
    int n = arr.Length;
     
    // declaring array of structure of type queries
    Query[] que = new Query[q + 1];
    que[0] = new Query(2, 1, 7);
    que[1] = new Query(2, 4, 5);
    que[2] = new Query(1, 3, 5);
    que[3] = new Query(2, 4, 4);
    AnswerQueries(arr, que, n, q);
  }
}
 
 
// This code is contribute by rishab


Javascript




// function to calculate the number of divisors of each number
function calcDivisors() {
  const divisors = new Array(100).fill(0);
  for (let i = 1; i < 100; i++) {
    for (let j = i; j < 100; j += i) {
      divisors[j] += 1;
    }
  }
  return divisors;
}
 
// function for updating the value
function update(x, val, n, BIT) {
  while (x <= n) {
    BIT[x] += val;
    x += (x & -x);
  }
}
 
// function for calculating the required sum between two indexes
function sum(x, BIT) {
  let s = 0;
  while (x > 0) {
    s += BIT[x];
    x -= (x & -x);
  }
  return s;
}
 
// function to return answer to queries
function answerQueries(arr, que, n, q) {
  // Declaring a Set
  const s = new Set();
  const BIT = new Array(n + 1).fill(0);
  const divisors = calcDivisors();
  for (let i = 1; i < n; i++) {
    // inserting indexes of those numbers which are greater than 2
    if (arr[i] > 2) {
      s.add(i);
    }
    update(i, arr[i], n, BIT);
  }
  for (let i = 0; i < q; i++) {
    // update query
    if (que[i][0] === 1) {
      const leftIndex = que[i][1];
      const rightIndex = que[i][2];
      for (const it of s.values()) {
        if (it >= leftIndex && it <= rightIndex) {
          // update the value of arr[i]
          update(it, divisors[arr[it]] - arr[it], n, BIT);
          arr[it] = divisors[arr[it]];
          if (arr[it] <= 2) {
            s.delete(it);
          }
        }
      }
    }
    // sum query
    else {
      console.log(sum(que[i][2], BIT) - sum(que[i][1] - 1, BIT));
    }
  }
}
 
// Driver Code
const arr = [0, 6, 4, 1, 10, 3, 2, 4];
const n = arr.length;
const que = [
  [2, 1, 7],
  [2, 4, 5],
  [1, 3, 5],
  [2, 4, 4]
];
 
// answer the Queries
answerQueries(arr, que, n, que.length);


Output

30
13
4

Time Complexity for answering Q queries will be O(Q * log(N)).

Auxiliary Space: O(N)



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads