You are on page 1of 6

Range updates with BIT / Fenwick Tree | Everything Under The Sun http://kartikkukreja.wordpress.com/2013/12/02/range-updates-with-bit...

Everything Under The Sun

A blog on CS concepts

Range updates with BIT / Fenwick Tree

December 2, 2013 by Kartik kukreja


I described implementation of BIT/Fenwick tree in an earlier post
(h p://kartikkukreja.wordpress.com/2013/05/11/bit-fenwick-tree-data-structure-c-implementation/)
as a way of maintaining cumulative frequency table, which allows operations like updating any
single element and querying sum of elements in a range [a...b] in logarithmic time. I recently found
out that this is only one of the ways of using a BIT. A BIT can in fact be operated in one of three
modes:

1. Point Updates and Range Queries

Given an array A of N numbers, we need to support adding a value v to any element A[p] and
querying the sum of numbers A[a] + A[a+1] + … + A[b], both operations in O(log N). Let ft[N+1]
denotes the underlying fenwick tree.

# Add v to A[p]
update(p, v):
for (; p <= N; p += p&(-p)) ft[p] += v

# Return sum A[1...b]


query(b):
sum = 0
for(; b > 0; b -= b&(-b)) sum += ft[b]
return sum

# Return sum A[a...b]


query(a, b):
return query(b) - query(a-1)

Take a look at C++ implementation (h p://pastebin.com/qzVeT7Zx).

2. Range Updates and Point queries

Given an array A of N numbers, we need to support adding a value v to each element A[a...b] and
querying the value of A[p], both operations in O(log N). Let ft[N+1] denote the underlying fenwick

1 of 6 5/28/2014 12:48 AM
Range updates with BIT / Fenwick Tree | Everything Under The Sun http://kartikkukreja.wordpress.com/2013/12/02/range-updates-with-bit...

tree.

# Add v to A[p]
update(p, v):
for (; p <= N; p += p&(-p)) ft[p] += v

# Add v to A[a...b]
update(a, b, v):
update(a, v)
update(b + 1, -v)

# Return A[b]
query(b):
sum = 0
for(; b > 0; b -= b&(-b)) sum += ft[b]
return sum

Explanation: update(p, v) will affect all p’ >= p. To limit the effect to a given range [a...b], we subtract
-v from all p’ > b by performing the operation update(b+1, -v).

See problem UPDATEIT (h p://www.spoj.com/problems/UPDATEIT/) which uses this idea.

Take a look at C++ implementation (h p://pastebin.com/dSSsTs9a).

3. Range Updates and Range Queries

Given an array A of N numbers, we need to support adding a value v to each element A[a...b] and
querying the sum of numbers A[a...b], both operations in O(log N). This can be done by using two
BITs B1[N+1], B2[N+1].

2 of 6 5/28/2014 12:48 AM
Range updates with BIT / Fenwick Tree | Everything Under The Sun http://kartikkukreja.wordpress.com/2013/12/02/range-updates-with-bit...

update(ft, p, v):
for (; p <= N; p += p&(-p)) ft[p] += v

# Add v to A[a...b]
update(a, b, v):
update(B1, a, v)
update(B1, b + 1, -v)
update(B2, a, v * (a-1))
update(B2, b + 1, -v * j)

query(ft, b):
sum = 0
for(; b > 0; b -= b&(-b)) sum += ft[b]
return sum

# Return sum A[1...b]


query(b):
return query(B1, b) * b - query(B2, b)

# Return sum A[a...b]


query(a, b):
return query(b) - query(a-1)

Explanation:

BIT B1 is used like in the earlier case with range updates/point queries such that query(B1, p) gives
A[p].

Consider a range update query: Add v to [a...b]. Let all elements initially be 0. Now, Sum(0…p) for
different p is as follows:

0<p<a:0
a <= p <= b : v * (p – (a – 1))
b < p <= N : v * (b – (a – 1))

Thus, for a given index p, if we have v * p, we can find Sum(0…p) by subtracting a value X from it
such that

0 < p < a : Sum(0..p) = 0, X = 0


a <= p <= b : Sum(0…p) = (v * p) – (v * (a-1)), X = v * (a-1)
b < p <= N: Sum(0…p) = (v * b) – (v * (a-1)), X = -(v * b) + (v * (a-1))

To maintain this extra factor X, we use another BIT B2 such that

Add v to [a...b] -> Update(B2, a, v * (a-1)) and Update(B2, b+1, -v * b)


Query(B2, p) gives the value X that must be subtracted from A[p] * p

See problem HORRIBLE (h p://www.spoj.com/problems/HORRIBLE/) which uses this idea.

Take a look at C++ implementation (h p://pastebin.com/8c0tfzTL).

3 of 6 5/28/2014 12:48 AM
Range updates with BIT / Fenwick Tree | Everything Under The Sun http://kartikkukreja.wordpress.com/2013/12/02/range-updates-with-bit...

References:

h p://apps.topcoder.com/forums/?module=Thread&threadID=715842&start=0&mc=8
(h p://apps.topcoder.com/forums/?module=Thread&threadID=715842&start=0&mc=8)
h p://programmingcontests.quora.com/Tutorial-Range-Updates-in-Fenwick-Tree
(h p://programmingcontests.quora.com/Tutorial-Range-Updates-in-Fenwick-Tree)

This entry was posted in Data Structures and tagged binary indexed tree, BIT, C++ implementation,
explanation, fenwick tree, HORRIBLE Spoj, point updates/range queries, range updates/point queries, range
updates/range queries, UPDATEIT Spoj. Bookmark the permalink.

15 thoughts on “Range updates with BIT / Fenwick Tree”

1. Anonymous says:
December 17, 2013 at 9:51 pm
h p://arxiv.org/abs/1311.6093

Reply
2. Anonymous says:
December 21, 2013 at 4:54 pm
Very nice tutorial :)
I have a doubt in the update(a,b,v) which adds v to all elements from index a to index b.Suppose
N=8 i.e there are total 8 elements. Now update(3,6,10) will update(add 10 to) elements from index
3 to index 6. update(3,6,10) can be performed as update(3,10) and update(7,-10). update(3,10) adds
10 to indexes 3,4 and 8. Similarly update(7,-10) adds -10 to indexes 7 and 8.Now to find sum(6)
which is the sum of all elements from index 1 to 6 , will be sum(5…6)+sum(1…..4) but index 5 and
6 were not updated. So I want to ask how is it giving the correct result?

Reply
kartik kukreja says:
December 21, 2013 at 7:29 pm
I think you are talking about the case of range updates and point queries. Note that the BIT is
not actually storing cumulative sum of true values of elements, only the updates that have
been applied to them so update(3,6,10) would not cause 10 to be added cumulatively for each
element in 3…6, just once. While querying for any element in 3..6, we should see the update
only once, which we do for element 6 in element 4.

In this case, query(6), query(5) and query(4) would use update at ft[4], query(3) would use
update at ft[3], queries to elements > 6 would see 2 updates 10 and -10.

I hope that clears the doubt. Typically a BIT is used to store the cumulative sum of elements
but we have changed its semantics here. The key idea is that if we update an element p, then
every element >= p would see that update.

Let me know if you need more help.

Reply
kartik kukreja says:
December 21, 2013 at 7:36 pm
You might already know this but just in case, update(a,b,v) does not literally add v to each

4 of 6 5/28/2014 12:48 AM
Range updates with BIT / Fenwick Tree | Everything Under The Sun http://kartikkukreja.wordpress.com/2013/12/02/range-updates-with-bit...

ft[a]..ft[b]. The semantics of update and query functions are such that an update(a,v) is seen by
query(a’) for each a’ >= a.

Reply
3. abhilash rudra says:
January 21, 2014 at 5:48 pm
awesome tutorial… (y)

Reply
4. Ishant Sharma says:
February 13, 2014 at 1:47 am
Nice tutorial (y)

Reply
5. Anonymous says:
April 4, 2014 at 11:15 am
VEry nice tutorial .But for range qury and range update “Why we are not doing :- update(a,v)
update(b+1,-v) for the update part and query(b)-query(a-1) for the sum part ..whats wrong in that
part???”

Reply
kartik kukreja says:
April 4, 2014 at 4:54 pm
Please read the explanation. In short, a BIT is a cumulative frequency table. update(a,v)
doesn’t literally add v to every bit[i], a<=i<=N, it just has the effect of doing so. To handle
range updates and range queries, we must use two BITs.

If we used a single BIT and performed range update: update(a,b,v) as update(a,v) and
update(b+1,-v), the update v would be visible only once in the range [a,b], it wonʹt be a range
update (it wonʹt have the effect of adding v cumulatively to each [a,b]). Similarly,
query(b)-query(a-1) would only be v, not v*(b-a+1).

Reply
6. Anonymous says:
April 4, 2014 at 9:27 pm
So it does depend on the question that whether we have to use SINGLE or DOUBLE depends on
whether it is Point update range query,range update point query or range update range query..??

Reply
kartik kukreja says:
April 4, 2014 at 10:29 pm
Yes. Point Update Range Query and Range Update Point Query cases can be handled with a
single BIT but Range Update Range Query requires two BITs.

Reply
7. Anonymous says:
April 5, 2014 at 4:00 pm
Thanks for pu ing this up.

Reply
8. Anonymous says:
April 21, 2014 at 6:33 pm
Why does in range update and point query , query(x) returns only the values at that position
only??

5 of 6 5/28/2014 12:48 AM
Range updates with BIT / Fenwick Tree | Everything Under The Sun http://kartikkukreja.wordpress.com/2013/12/02/range-updates-with-bit...

What is the reason??

Reply
kartik kukreja says:
April 21, 2014 at 9:55 pm
The question as I understand is this: why the same query(x) function calculates sum(A[1..x])
for point-update-range-query while it calculates A[x] for range-update-point-query?

update(x,v) and query(x) functions are common to both the cases so they must have the same
behavior too. update(x,v) adds v to some elements ft[i] (i≥x) such that when you call query(i)
(i≥x), you will see this update v exactly once and thus count it exactly once. query(x) adds
some elements ft[i] (i≤x) such that each update to any element i≤x is seen exactly once.

For the point-update-range-query case, all update(x,v) are visible to x’≥x so when you call
query(c), you effectively add all the updates applied to all elements 1≤i≤c which is nothing but
the sum of A[1..c].

However, in the case of range-update-point-query, updates can be cancelled off.


updates(a,b,v) is only visible exactly once inside the range a..b (effected by adding -v to ft[i]
for i>b). Now, when you call query(c), it still sums the frequencies from 1 to c but their
meaning is now different. If it sees an update v during summing frequencies, it is because that
index lied in the range of some range update a..b applied some time before. Since the value is
seen only once, it is as if v is added to only that index. This explains why query(c) now
calculates A[c]. It is still calculating sum of frequencies but they have a different meaning now.

I hope this makes sense to you. Thanks for showing interest.

Reply
9. Ashish Tilokani says:
May 22, 2014 at 1:23 am
I am not ge ing the correct answer if I take in p & q and pass p+1 & q+1 to the 2 functions in main
to make it 1 based index. Why is it so?

Reply
Ashish Tilokani says:
May 22, 2014 at 1:47 am
solved … just realizes that they are already 1- based indexed

Reply

Blog at WordPress.com. | The Sundance Theme.

Follow

Follow “Everything Under The Sun”

Powered by WordPress.com

6 of 6 5/28/2014 12:48 AM

You might also like