Range Sum Queries and Update with Square Root
Last Updated :
30 Jan, 2023
Given an array A of N integers and number of queries Q. You have to answer two types of queries.
- Update [l, r] – for every i in range from l to r update Ai with sqrt(Ai), where sqrt(Ai) represents the square root of Ai in integral form.
- Query [l, r] – calculate the sum of all numbers ranging between l and r in array A.
Prerequisite: Binary Indexed Trees | Segment Trees
Examples:
Input: A[] = { 4, 5, 1, 2, 4 }, Q = {{2, 1, 5}, {1, 1, 2}, {1, 2, 4}, {2, 1, 5}}
Output: 16
9
Considering 1-based indexing, first query is to calculate sum of numbers from A1 to A5
which is 4 + 5 + 1 + 2 + 4 = 16.
Second query is to update A1 to A2 with its square root. Now, array becomes A[] = { 2, 2, 1, 2, 4 }.
Similarly, third query is to update A2 to A4 with its square root. Now, array becomes A[] = { 2, 1, 1, 1, 4 }.
Fourth query is to calculate sum of numbers from A1 to A5 which is 2 + 1 + 1 + 1 + 4 = 9.
Input: A[] = { 4, 9, 25, 36 }, Q = {{1, 2, 4}, {2, 1, 4}}
Output: 18
Naive Approach: A simple solution is to run a loop from l to r and calculate sum of elements in the given range. To update a value, simple replace arr[i] with its square root, i.e., arr[i] = sqrt[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. Now, for each update operation the key observation is that the number 1 will have 1 as its square root, so if it exists in the range of update query, it doesn’t need to be updated. We will use a set to store the index of only those numbers which are greater than 1 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 1 as its square root then after updating it, remove it from the set as it will always be 1 even after any next update query. For sum query operation, simply do query(r) – query(l – 1).
Below is the implementation of the above approach:
CPP
// CPP program to calculate sum
// in an interval and update with
// square root
#include <bits/stdc++.h>
using namespace std;
// Maximum size of input array
const int MAX = 100;
int BIT[MAX + 1];
// structure for queries with members type,
// leftIndex, rightIndex of the query
struct queries {
int type, l, r;
};
// 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 1
if (arr[i] > 1)
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 square root
update(*it, (int)sqrt(arr[*it]) - arr[*it], n);
arr[*it] = (int)sqrt(arr[*it]);
// if updated value becomes equal to 1
// remove it from the set
if (arr[*it] == 1)
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()
{
int q = 4;
// input array using 1-based indexing
int arr[] = { 0, 4, 5, 1, 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 = 5;
que[1].type = 1, que[1].l = 1, que[1].r = 2;
que[2].type = 1, que[2].l = 2, que[2].r = 4;
que[3].type = 2, que[3].l = 1, que[3].r = 5;
// answer the Queries
answerQueries(arr, que, n, q);
return 0;
}
Java
import java.util.*;
import java.util.stream.*;
class Program {
// Maximum size of input array
static int MAX = 100;
static int[] BIT = new int[MAX + 1];
// structure for queries with members type,
// leftIndex, rightIndex of the query
static class queries { public int type, l, r;
public queries(int t_val, int l_val, int r_val)
{
type = t_val;
l = l_val;
r = r_val;
}
}
// function for updating the value
static void update(int x, int val, int n) {
for (; x <= n; x += x & -x) {
BIT[x] += val;
}
}
// function for calculating the required
// sum between two indexes
static int sum(int x) {
int s = 0;
for (; x > 0; x -= x & -x) {
s += BIT[x];
}
return s;
}
// function to return answer to queries
static void answerQueries(int[] arr, queries[] que, int n, int q) {
// Declaring a Set
HashSet<Integer> s = new HashSet<Integer>();
for (int i = 1; i < n; i++) {
// inserting indexes of those numbers
// which are greater than 1
if (arr[i] > 1)
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
final var val = que[i].l;
Stream<Integer> st = s.stream().filter(x -> x >= val);
int it = st.findFirst().orElse(0);
// if it crosses the right index of
// query or end of set, then break
if (it == 0 || it > que[i].r)
break;
que[i].l = it;
// update the value of arr[i] to
// its square root
update(it, (int)Math.sqrt(arr[it]) - arr[it], n);
arr[it] = (int)Math.sqrt(arr[it]);
// if updated value becomes equal to 1
// remove it from the set
if (arr[it] == 1)
s.remove(it);
// increment the index
que[i].l++;
}
}
// sum query
else {
System.out.println(sum(que[i].r) - sum(que[i].l - 1));
}
}
}
// Driver Code
public static void main(String[] args) {
int q = 4;
// input array using 1-based indexing
int[] arr = { 0, 4, 5, 1, 2, 4 };
int n = arr.length;
// declaring array of structure of type queries
queries[] que = new queries[q + 1];
que[0] = new queries(2, 1, 5);
que[1] = new queries(1, 1, 2);
que[2] = new queries(1, 2, 4);
que[3] = new queries(2, 1, 5);
// answer the Queries
answerQueries(arr, que, n, q);
}
}
Python3
# Python program to calculate sum
# in an interval and update with
# square root
from typing import List
import bisect
from math import sqrt, floor
# Maximum size of input array
MAX = 100
BIT = [0 for _ in range(MAX + 1)]
# structure for queries with members type,
# leftIndex, rightIndex of the query
class queries:
def __init__(self, type: int = 0, l: int = 0, r: int = 0) -> None:
self.type = type
self.l = l
self.r = r
# function for updating the value
def update(x: int, val: int, n: int) -> None:
a = x
while a <= n:
BIT[a] += val
a += a & -a
# function for calculating the required
# sum between two indexes
def sum(x: int) -> int:
s = 0
a = x
while a:
s += BIT[a]
a -= a & -a
return s
# function to return answer to queries
def answerQueries(arr: List[int], que: List[queries], n: int, q: int) -> None:
# Declaring a Set
s = set()
for i in range(1, n):
# inserting indexes of those numbers
# which are greater than 1
if (arr[i] > 1):
s.add(i)
update(i, arr[i], n)
for i in range(q):
# update query
if (que[i].type == 1):
while True:
ss = list(sorted(s))
# find the left index of query in
# the set using binary search
# auto it = s.lower_bound(que[i].l);
it = bisect.bisect_left(ss, que[i].l)
# if it crosses the right index of
# query or end of set, then break
if it == len(s) or ss[it] > que[i].r:
break
que[i].l = ss[it]
# update the value of arr[i] to
# its square root
update(ss[it], floor(sqrt(arr[ss[it]]) - arr[ss[it]]), n)
arr[ss[it]] = floor(sqrt(arr[ss[it]]))
# if updated value becomes equal to 1
# remove it from the set
if (arr[ss[it]] == 1):
s.remove(ss[it])
# increment the index
que[i].l += 1
# sum query
else:
print(sum(que[i].r) - sum(que[i].l - 1))
# Driver Code
if __name__ == "__main__":
q = 4
# input array using 1-based indexing
arr = [0, 4, 5, 1, 2, 4]
n = len(arr)
# declaring array of structure of type queries
que = [queries() for _ in range(q + 1)]
que[0].type, que[0].l, que[0].r = 2, 1, 5
que[1].type, que[1].l, que[1].r = 1, 1, 2
que[2].type, que[2].l, que[2].r = 1, 2, 4
que[3].type, que[3].l, que[3].r = 2, 1, 5
# answer the Queries
answerQueries(arr, que, n, q)
# This code is contributed by sanjeev2552
C#
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
// Maximum size of input array
const int MAX = 100;
static int[] BIT = new int[MAX + 1];
// structure for queries with members type,
// leftIndex, rightIndex of the query
struct queries { public int type, l, r; }
// function for updating the value
static void update(int x, int val, int n)
{
for (; x <= n; x += x & -x) {
BIT[x] += val;
}
}
// function for calculating the required
// sum between two indexes
static int sum(int x)
{
int s = 0;
for (; x > 0; x -= x & -x) {
s += BIT[x];
}
return s;
}
// function to return answer to queries
static void answerQueries(int[] arr, queries[] que,
int n, int q)
{
// Declaring a Set
var s = new HashSet<int>();
for (int i = 1; i < n; i++) {
// inserting indexes of those numbers
// which are greater than 1
if (arr[i] > 1)
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.Where(x => x >= que[i].l)
.FirstOrDefault();
// if it crosses the right index of
// query or end of set, then break
if (it == 0 || it > que[i].r)
break;
que[i].l = it;
// update the value of arr[i] to
// its square root
update(it,
(int)Math.Sqrt(arr[it])
- arr[it],
n);
arr[it] = (int)Math.Sqrt(arr[it]);
// if updated value becomes equal to 1
// remove it from the set
if (arr[it] == 1)
s.Remove(it);
// increment the index
que[i].l++;
}
}
// sum query
else {
Console.WriteLine(sum(que[i].r)
- sum(que[i].l - 1));
}
}
}
// Driver Code
static void Main(string[] args)
{
int q = 4;
// input array using 1-based indexing
int[] arr = { 0, 4, 5, 1, 2, 4 };
int n = arr.Length;
// declaring array of structure of type queries
var que = new queries[q + 1];
que[0].type = 2;
que[0].l = 1;
que[0].r = 5;
que[1].type = 1;
que[1].l = 1;
que[1].r = 2;
que[2].type = 1;
que[2].l = 2;
que[2].r = 4;
que[3].type = 2;
que[3].l = 1;
que[3].r = 5;
// answer the Queries
answerQueries(arr, que, n, q);
}
}
// This code is contributed by phasing17
JavaScript
// JavaScript program to calculate sum
// in an interval and update with
// square root
// Maximum size of input array
let MAX = 100;
let BIT = new Array(MAX + 1).fill(0);
function lower_bound(arr, ele)
{
for (var i = 0; i < arr.length; i++)
{
if (arr[i] >= ele)
return i;
}
return arr.length - 1;
}
// structure for queries with members type,
// leftIndex, rightIndex of the query
class queries
{
constructor(type, l, r)
{
this.type = type;
this.l = l;
this.r = r;
}
}
// function for updating the value
function update(BIT, x, val, n)
{
var a = x;
while (a <= n)
{
BIT[a] += val;
a += (a & -a);
}
return BIT;
}
// function for calculating the required
// sum between two indexes
function sum(x)
{
var s = 0;
var a = x;
while (a > 0)
{
s += BIT[a];
a -= (a & -a);
}
return s;
}
// function to return answer to queries
function answerQueries(arr, que, n, q)
{
// Declaring a Set
let s = new Set();
for (var i = 1; i < n; i++)
{
// inserting indexes of those numbers
// which are greater than 1
if (arr[i] > 1)
s.add(i);
BIT = update(BIT, i, arr[i], n);
}
for (var i = 0; i < q; i++)
{
// update query
if (que[i].type == 1)
{
while (true)
{
var ss = Array.from(s);
ss.sort();
// find the left index of query in
// the set using binary search
// auto it = s.lower_bound(que[i].l);
let it = lower_bound(ss, que[i].l);
// if it crosses the right index of
// query or end of set, then break
if (it == s.length || ss[it] > que[i].r)
break;
que[i].l = ss[it];
// update the value of arr[i] to
// its square root
BIT = update(BIT, ss[it], (Math.pow(arr[ss[it]], 0.5)) - arr[ss[it]], n);
arr[ss[it]] = (Math.pow(arr[ss[it]], 0.5));
// if updated value becomes equal to 1
// remove it from the set
if (arr[ss[it]] == 1)
arr.splice(ss[it], 1);
// increment the index
que[i].l += 1;
}
}
// sum query
else
console.log(Math.floor(sum(que[i].r) - sum(que[i].l - 1)));
}
}
// Driver Code
let q = 4;
// input array using 1-based indexing
let arr = [0, 4, 5, 1, 2, 4];
let n = arr.length;
// declaring array of structure of type queries
let que = [new queries(2, 1, 5), new queries(1, 1, 2), new queries(1, 2, 4),
new queries(2, 1, 5)];
// answer the Queries
answerQueries(arr, que, n, q);
// This code is contributed by phasing17
Complexity Analysis:
- Time Complexity: O(logN) per query
- Auxiliary Space: O(N)
Similar Reads
Range and Update Sum Queries with Factorial
Given an array arr[] of N integers and number of queries Q. The task is to answer three types of queries. Update [l, r] â for every i in range [l, r] increment arr[i] by 1.Update [l, val] â change the value of arr[l] to val.Query [l, r] â calculate the sum of arr[i]! % 109 for all i in range [l, r]
15+ min read
Range sum queries without updates
Given an array arr of integers of size n. We need to compute the sum of elements from index i to index j. The queries consisting of i and j index values will be executed multiple times.Examples: Input : arr[] = {1, 2, 3, 4, 5} i = 1, j = 3 i = 2, j = 4Output : 9 12 Input : arr[] = {1, 2, 3, 4, 5} i
6 min read
Segment Tree | Set 2 (Range Maximum Query with Node Update)
Given an array arr[0 . . . n-1]. Find the maximum of elements from index l to r where 0 <= l <= r <= n-1. Also, change the value of a specified element of the array to a new value x. We need to do arr[i] = x where 0 <= i <= n-1 and then find the maximum element of given range with upd
15+ min read
Sum of Interval and Update with Number of Divisors
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 give
12 min read
Binary Indexed Tree : Range Update and Range Queries
Given an array arr[0..N-1]. The following operations need to be performed. update(l, r, val): Add âvalâ to all the elements in the array from [l, r].getRangeSum(l, r): Find the sum of all elements in the array from [l, r].Initially, all the elements in the array are 0. Queries can be in any order, i
15+ min read
Array range queries to find the number of perfect square elements with updates
Given an array arr[] of N integers, the task is to perform the following two queries: query(start, end): Print the number of perfect square numbers in the sub-array from start to endupdate(i, x): Add x to the array element referenced by array index i, that is: arr[i] = x Note: 0 based indexing is fo
15+ min read
Iterative Segment Tree (Range Maximum Query with Node Update)
Given an array arr[0 . . . n-1]. The task is to perform the following operation: Find the maximum of elements from index l to r where 0 <= l <= r <= n-1.Change value of a specified element of the array to a new value x. Given i and x, change A[i] to x, 0 <= i <= n-1. Examples: Input:
14 min read
Sum and Update Queries on 2D Matrix
Given a 2D matrix mat[][] of size NXN with all its elements initialized to 0, the task is to answer Q queries. Each query[i] can be one of the following types: Type 1 [1, x, y, ele]: Update the value of cell(x, y) to val.Type 2 [2, x1, y1 ,x2, y2]: Print the sum of the submatrix (x1, y1) to (x2, y2)
12 min read
Sum of elements whose square root is present in the array
Given an array arr[], the task is to find the sum of all those elements from the given array whose square root is present in the same array. Examples: Input: arr[] = {1, 2, 3, 4, 6, 9, 10} Output: 13 4 and 9 are the only numbers whose square roots 2 and 3 are present in the array Input: arr[] = {4,
9 min read
Range Minimum Query (Square Root Decomposition and Sparse Table)
We have an array arr[0 . . . n-1]. We should be able to efficiently find the minimum value from index L (query start) to R (query end) where 0 <= L <= R <= n-1. Consider a situation when there are many range queries. Example: Input: arr[] = {7, 2, 3, 0, 5, 10, 3, 12, 18}; query[] = [0, 4],
15+ min read