Sum of Interval and Update with Number of Divisors - GeeksforGeeks

05 Apr, 2018
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 Ai2. 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).
// 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 querystruct queries{    int type, l, r;};  // function to calculate the number // of divisors of each numbervoid calcDivisors(){    for (int i = 1; i < 100; i++) {        for (int j = i; j < 100; j += i) {            divisors[j]++;         }    }}  // function for updating the valuevoid 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 indexesint sum(int x){    int s = 0;    for (x; x > 0; x -= x&-x) {        s += BIT[x];     }    return s;}  // function to return answer to queriesvoid 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 Codeint 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;}
30
13
4

Time Complexity for answering Q queries will be O(Q * log(N)).
array-range-queries
Binary Indexed Tree
Segment-Tree
Technical Scripter
Tree
Tree
Binary Indexed Tree
Segment-Tree
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Tree Traversals (Inorder, Preorder and Postorder)
AVL Tree | Set 1 (Insertion)
Binary Tree | Set 1 (Introduction)
Level Order Binary Tree Traversal
Binary Tree | Set 3 (Types of Binary Tree)
Inorder Tree Traversal without Recursion
Binary Tree | Set 2 (Properties)
Write a Program to Find the Maximum Depth or Height of a Tree
Decision Tree
A program to check if a binary tree is BST or not