给定一个数组arr [0..n-1]。需要执行以下操作。
- update(l,r,val) :将[val]从[l,r]添加到数组中的所有元素。
- getRangeSum(l,r) :从[l,r]中查找数组中所有元素的总和。
最初,数组中的所有元素均为0。查询可以按任何顺序进行,即,在范围求和之前可以进行许多更新。
例子:
Input : n = 5 // {0, 0, 0, 0, 0}
Queries: update : l = 0, r = 4, val = 2
update : l = 3, r = 4, val = 3
getRangeSum : l = 2, r = 4
Output: Sum of elements of range [2, 4] is 12
Explanation : Array after first update becomes
{2, 2, 2, 2, 2}
Array after second update becomes
{2, 2, 2, 5, 5}
在上一篇文章中,我们讨论了使用BIT的范围更新和点查询解决方案。
rangeUpdate(l,r,val):我们在元素的索引“ l”处添加“ val”。我们从索引为“ r + 1”的元素中减去“ val”。
getElement(index)[或getSum()]:我们将元素的总和从0返回到可以使用BIT快速获得的索引。
我们可以使用getSum()查询来计算rangeSum()。
rangeSum(l,r)= getSum(r)– getSum(l-1)
一个简单的解决方案是使用上一篇文章中讨论的解决方案。范围更新查询是相同的。范围总和查询可以通过对范围内的所有元素进行获取查询来实现。
一个有效的解决方案是确保两个查询都可以在O(Log n)时间内完成。我们使用前缀和获得范围和。如何确保以某种方式完成更新,以便可以快速完成前缀总和?考虑以下情况:在范围[l,r]上进行范围更新之后,需要前缀总和[0,k](其中0 <= k 情况1 :0 情况2 :l <= k <= r 如何得到这个结果? 情况3 :k> r 观察结果: 情况2:总和增加val * k – val *(l-1)。我们可以找到“ val”,类似于在范围更新和点查询文章中找到第i个元素。因此,我们为范围更新和点查询保留一个BIT,此BIT将有助于找到第k个索引的值。现在计算val * k,如何处理多余项val *(l-1)? 情况3:情况3的总和增加了“ val * r – val *(l-1)”,可以使用BIT2获得该项的值。代替添加,我们减去“ val *(l-1)– val * r”,因为我们可以像情况2一样通过添加val *(l-1)从BIT2中获得此值,并在每次更新中减去val * r手术。 上述想法的实施 输出: 时间复杂度:O(q * log(n)),其中q是查询数。
考虑一个例子: Add 2 to range [2, 4], the resultant array would be:
0 0 2 2 2
If k = 3
Sum from [0, k] = 4
只需将第l个索引的val添加到第k个索引。更新查询后,总和增加“ val *(k)– val *(l-1)”。
对于这种情况,我们需要将第l个索引的“ val”添加到第r个索引。由于更新查询,总和增加“ val * r – val *(l-1)”。
情况1:很简单,因为总和将保持与更新前相同。
为了处理这个额外的期限,我们保留了另一个BIT(BIT2)。在第l个索引处更新val *(l-1),因此对BIT2执行getSum查询时,结果将为val *(l-1)。Update Query
Update(BITree1, l, val)
Update(BITree1, r+1, -val)
UpdateBIT2(BITree2, l, val*(l-1))
UpdateBIT2(BITree2, r+1, -val*r)
Range Sum
getSum(BITTree1, k) *k) - getSum(BITTree2, k)
C++
// C++ program to demonstrate Range Update
// and Range Queries using BIT
#include
Java
// Java program to demonstrate Range Update
// and Range Queries using BIT
import java.util.*;
class GFG
{
// Returns sum of arr[0..index]. This function assumes
// that the array is preprocessed and partial sums of
// array elements are stored in BITree[]
static int getSum(int BITree[], int index)
{
int sum = 0; // Initialize result
// index in BITree[] is 1 more than the index in arr[]
index = index + 1;
// Traverse ancestors of BITree[index]
while (index > 0)
{
// Add current element of BITree to sum
sum += BITree[index];
// Move index to parent node in getSum View
index -= index & (-index);
}
return sum;
}
// Updates a node in Binary Index Tree (BITree) at given
// index in BITree. The given value 'val' is added to
// BITree[i] and all of its ancestors in tree.
static void updateBIT(int BITree[], int n, int index, int val)
{
// index in BITree[] is 1 more than the index in arr[]
index = index + 1;
// Traverse all ancestors and add 'val'
while (index <= n)
{
// Add 'val' to current node of BI Tree
BITree[index] += val;
// Update index to that of parent in update View
index += index & (-index);
}
}
// Returns the sum of array from [0, x]
static int sum(int x, int BITTree1[], int BITTree2[])
{
return (getSum(BITTree1, x) * x) - getSum(BITTree2, x);
}
static void updateRange(int BITTree1[], int BITTree2[], int n,
int val, int l, int r)
{
// Update Both the Binary Index Trees
// As discussed in the article
// Update BIT1
updateBIT(BITTree1, n, l, val);
updateBIT(BITTree1, n, r + 1, -val);
// Update BIT2
updateBIT(BITTree2, n, l, val * (l - 1));
updateBIT(BITTree2, n, r + 1, -val * r);
}
static int rangeSum(int l, int r, int BITTree1[], int BITTree2[])
{
// Find sum from [0,r] then subtract sum
// from [0,l-1] in order to find sum from
// [l,r]
return sum(r, BITTree1, BITTree2) -
sum(l - 1, BITTree1, BITTree2);
}
static int[] constructBITree(int n)
{
// Create and initialize BITree[] as 0
int []BITree = new int[n + 1];
for (int i = 1; i <= n; i++)
BITree[i] = 0;
return BITree;
}
// Driver Program to test above function
public static void main(String[] args)
{
int n = 5;
// Contwo BIT
int []BITTree1;
int []BITTree2;
// BIT1 to get element at any index
// in the array
BITTree1 = constructBITree(n);
// BIT 2 maintains the extra term
// which needs to be subtracted
BITTree2 = constructBITree(n);
// Add 5 to all the elements from [0,4]
int l = 0 , r = 4 , val = 5;
updateRange(BITTree1, BITTree2, n, val, l, r);
// Add 2 to all the elements from [2,4]
l = 2 ; r = 4 ; val = 10;
updateRange(BITTree1, BITTree2, n, val, l, r);
// Find sum of all the elements from
// [1,4]
l = 1 ; r = 4;
System.out.print("Sum of elements from [" + l
+ "," + r+ "] is ");
System.out.print(rangeSum(l, r, BITTree1, BITTree2)+ "\n");
}
}
// This code is contributed by 29AjayKumar
Python3
# Python program to demonstrate Range Update
# and Range Queries using BIT
# Returns sum of arr[0..index]. This function assumes
# that the array is preprocessed and partial sums of
# array elements are stored in BITree[]
def getSum(BITree: list, index: int) -> int:
summ = 0 # Initialize result
# index in BITree[] is 1 more than the index in arr[]
index = index + 1
# Traverse ancestors of BITree[index]
while index > 0:
# Add current element of BITree to sum
summ += BITree[index]
# Move index to parent node in getSum View
index -= index & (-index)
return summ
# Updates a node in Binary Index Tree (BITree) at given
# index in BITree. The given value 'val' is added to
# BITree[i] and all of its ancestors in tree.
def updateBit(BITTree: list, n: int, index: int, val: int) -> None:
# index in BITree[] is 1 more than the index in arr[]
index = index + 1
# Traverse all ancestors and add 'val'
while index <= n:
# Add 'val' to current node of BI Tree
BITTree[index] += val
# Update index to that of parent in update View
index += index & (-index)
# Returns the sum of array from [0, x]
def summation(x: int, BITTree1: list, BITTree2: list) -> int:
return (getSum(BITTree1, x) * x) - getSum(BITTree2, x)
def updateRange(BITTree1: list, BITTree2: list, n: int, val: int, l: int,
r: int) -> None:
# Update Both the Binary Index Trees
# As discussed in the article
# Update BIT1
updateBit(BITTree1, n, l, val)
updateBit(BITTree1, n, r + 1, -val)
# Update BIT2
updateBit(BITTree2, n, l, val * (l - 1))
updateBit(BITTree2, n, r + 1, -val * r)
def rangeSum(l: int, r: int, BITTree1: list, BITTree2: list) -> int:
# Find sum from [0,r] then subtract sum
# from [0,l-1] in order to find sum from
# [l,r]
return summation(r, BITTree1, BITTree2) - summation(
l - 1, BITTree1, BITTree2)
# Driver Code
if __name__ == "__main__":
n = 5
# BIT1 to get element at any index
# in the array
BITTree1 = [0] * (n + 1)
# BIT 2 maintains the extra term
# which needs to be subtracted
BITTree2 = [0] * (n + 1)
# Add 5 to all the elements from [0,4]
l = 0
r = 4
val = 5
updateRange(BITTree1, BITTree2, n, val, l, r)
# Add 2 to all the elements from [2,4]
l = 2
r = 4
val = 10
updateRange(BITTree1, BITTree2, n, val, l, r)
# Find sum of all the elements from
# [1,4]
l = 1
r = 4
print("Sum of elements from [%d,%d] is %d" %
(l, r, rangeSum(l, r, BITTree1, BITTree2)))
# This code is contributed by
# sanjeev2552
C#
// C# program to demonstrate Range Update
// and Range Queries using BIT
using System;
class GFG
{
// Returns sum of arr[0..index]. This function assumes
// that the array is preprocessed and partial sums of
// array elements are stored in BITree[]
static int getSum(int []BITree, int index)
{
int sum = 0; // Initialize result
// index in BITree[] is 1 more than
// the index in []arr
index = index + 1;
// Traverse ancestors of BITree[index]
while (index > 0)
{
// Add current element of BITree to sum
sum += BITree[index];
// Move index to parent node in getSum View
index -= index & (-index);
}
return sum;
}
// Updates a node in Binary Index Tree (BITree) at given
// index in BITree. The given value 'val' is added to
// BITree[i] and all of its ancestors in tree.
static void updateBIT(int []BITree, int n,
int index, int val)
{
// index in BITree[] is 1 more than
// the index in []arr
index = index + 1;
// Traverse all ancestors and add 'val'
while (index <= n)
{
// Add 'val' to current node of BI Tree
BITree[index] += val;
// Update index to that of
// parent in update View
index += index & (-index);
}
}
// Returns the sum of array from [0, x]
static int sum(int x, int []BITTree1,
int []BITTree2)
{
return (getSum(BITTree1, x) * x) -
getSum(BITTree2, x);
}
static void updateRange(int []BITTree1,
int []BITTree2, int n,
int val, int l, int r)
{
// Update Both the Binary Index Trees
// As discussed in the article
// Update BIT1
updateBIT(BITTree1, n, l, val);
updateBIT(BITTree1, n, r + 1, -val);
// Update BIT2
updateBIT(BITTree2, n, l, val * (l - 1));
updateBIT(BITTree2, n, r + 1, -val * r);
}
static int rangeSum(int l, int r,
int []BITTree1,
int []BITTree2)
{
// Find sum from [0,r] then subtract sum
// from [0,l-1] in order to find sum from
// [l,r]
return sum(r, BITTree1, BITTree2) -
sum(l - 1, BITTree1, BITTree2);
}
static int[] constructBITree(int n)
{
// Create and initialize BITree[] as 0
int []BITree = new int[n + 1];
for (int i = 1; i <= n; i++)
BITree[i] = 0;
return BITree;
}
// Driver Code
public static void Main(String[] args)
{
int n = 5;
// Contwo BIT
int []BITTree1;
int []BITTree2;
// BIT1 to get element at any index
// in the array
BITTree1 = constructBITree(n);
// BIT 2 maintains the extra term
// which needs to be subtracted
BITTree2 = constructBITree(n);
// Add 5 to all the elements from [0,4]
int l = 0 , r = 4 , val = 5;
updateRange(BITTree1, BITTree2, n, val, l, r);
// Add 2 to all the elements from [2,4]
l = 2 ; r = 4 ; val = 10;
updateRange(BITTree1, BITTree2, n, val, l, r);
// Find sum of all the elements from
// [1,4]
l = 1 ; r = 4;
Console.Write("Sum of elements from [" + l +
"," + r + "] is ");
Console.Write(rangeSum(l, r, BITTree1,
BITTree2) + "\n");
}
}
// This code is contributed by 29AjayKumar
Sum of elements from [1,4] is 50