Honors Track: Competitive Programming & Problem Solving Binary Indexed Trees Christiaan Dirkx
Contents Problem Introduction Formalization Naive Implementation Binary Indexed Trees Binary Intermezzo Operations Extenstions Problems
Why Binary Indexed Trees? Consider the following problem: A list of values A 1 3 -1 4 Sum of all elements in A? Sum of the first 3 elements in A? Sum of element 2 through 7?
Formalisation Abstact Data Type We want to store a collection C of elements, each with an associated index (integer value). Operations Get(S, i): gets the value of element in S with index i Sum(S, i): gets the sum of all elements in S with index ≤ i Update(S, i, v): updates the value of element in S with index i to value v
Formalisation Abstact Data Type We want to store a collection C of elements, each with an associated index (integer value). Operations Get(S, i): gets the value of element in S with index i Sum(S, i): gets the sum of all elements in S with index ≤ i Update(S, i, v): updates the value of element in S with index i to value v Sum(S, a, b)?: gets the sum of all elements in S with index i, a ≤ i ≤ b
Formalisation Abstact Data Type We want to store a collection C of elements, each with an associated index (integer value). Operations Get(S, i): gets the value of element in S with index i Sum(S, i): gets the sum of all elements in S with index ≤ i Update(S, i, v): updates the value of element in S with index i to value v Sum(S, a, b): Sum(S, b) – Sum(S, a - 1)
Implementation How can we implement this ADT? Heaps! (Not quite)
Implementation A: 1 3 -1 4 1 4 3 3 7 8 9 Aggregation array
Implementation A: Can we improve? Aggregation array 1 3 -1 4 1 4 3 3 7 1 3 -1 4 1 4 3 3 7 8 9 Aggregation array Complexity? Get(S, i): O(1) Can we improve? Sum(S, i): O(1) Update(S, i, v): O(n)
Implementation A: Can we improve? Aggregation array 1 3 -1 4 1 4 3 3 7 1 3 -1 4 1 4 3 3 7 8 9 Aggregation array Complexity? Get(S, i): O(log n) Can we improve? Sum(S, i): O(log n) Update(S, i): O(log n)
Binary Indexed Tree ? Change the recurrence relation The key idea: Aggregation array: Sum(S, 0): Get(S, 0) Sum(S, i): Sum(S, i-1, i) + Sum(S, i-1)
Binary Indexed Tree ? ? Change the recurrence relation The key idea: Aggregation array: Sum(S, 0): Get(S, 0) Sum(S, i): Get(S, i) + Sum(S, i-1) ? Binary indexed tree: O(log n)
Binary recurrence Sum(S, 13): Sum(S, 12, 13) + Sum(S, 12) Consider the number 13 Sum(S, 13): Sum(S, 12, 13) + Sum(S, 12) Sum(S, 12): Sum(S, 8, 12) + Sum(S, 8) Sum(S, 8): Sum(S, 0, 8) + Sum(S, 0) Why? In binary: 13 1101 12 1100 8 1000
Binary recurrence Sum(S, 1101): Sum(S, 1100, 1101) + Sum(S, 1100) Consider the number 13 Sum(S, 1101): Sum(S, 1100, 1101) + Sum(S, 1100) Sum(S, 1100): Sum(S, 1000, 1100) + Sum(S, 1000) Sum(S, 1000): Sum(S, 0000, 1000) + Sum(S, 0000) O(log n)
Visualization 0000 0001 0010 0100 1000 0011 0101 0110 0111 A: 1 3 -1 4
Visualization 1 3 9 3 4 1 A: 1 3 -1 4 1 4 3 3 7 8 9
Visualization 1 3 9 3 4 1 A: 1 3 -1 4 1 4 3 3 7 8 9
Visualization T: A: But how should we encode the index? 1 3 3 4 1 9 1 1 3 3 4 1 9 But how should we encode the index? A: 1 3 -1 4 1 4 3 3 7 8 9
We want to iteratively get the least significant bit Binary Intermezzo Binary number: 1 0 1 0 1 1 0 1 most significant bit least significant bit 13 1 1 0 1 12 1 1 0 0 8 1 0 0 0 We want to iteratively get the least significant bit
Binary Intermezzo i : 0 1 0 0 1 1 0 0 ~i : 1 0 1 1 0 0 1 1 -i : Next index: i : 0 1 0 0 1 1 0 0 ~i : 1 0 1 1 0 0 1 1 -i : 1 0 1 1 0 1 0 0 i & -i : 0 0 0 0 0 1 0 0 i - (i & -i) : 0 1 0 0 1 0 0 0
Sum(S, i) A: T: Sum(S, i) Sum(S, 7) 1 3 -1 4 1 1 1 3 3 4 1 9 sum: 0 1 3 -1 4 1 1 T: 1 3 3 4 1 9 Sum(S, i) Sum(S, 7) int sum(int idx) { int sum = 0; while (idx > 0) { sum += T[idx]; idx -= (idx & -idx); } return sum; sum: 0 idx: 7 (0111)
Sum(S, i) A: T: Sum(S, i) Sum(S, 7) 1 3 -1 4 1 1 1 3 3 4 1 9 sum: 1 1 3 -1 4 1 1 T: 1 3 3 4 1 9 Sum(S, i) Sum(S, 7) int sum(int idx) { int sum = 0; while (idx > 0) { sum += T[idx]; idx -= (idx & -idx); } return sum; sum: 1 idx: 7 (0111)
Sum(S, i) A: T: Sum(S, i) Sum(S, 7) 1 3 -1 4 1 1 1 3 3 4 1 9 sum: 5 1 3 -1 4 1 1 T: 1 3 3 4 1 9 Sum(S, i) Sum(S, 7) int sum(int idx) { int sum = 0; while (idx > 0) { sum += T[idx]; idx -= (idx & -idx); } return sum; sum: 5 idx: 6 (0110)
Sum(S, i) A: T: Sum(S, i) Sum(S, 7) 1 3 -1 4 1 1 1 3 3 4 1 9 sum: 8 1 3 -1 4 1 1 T: 1 3 3 4 1 9 Sum(S, i) Sum(S, 7) int sum(int idx) { int sum = 0; while (idx > 0) { sum += T[idx]; idx -= (idx & -idx); } return sum; sum: 8 idx: 4 (0100)
Sum(S, i) A: T: Sum(S, i) Sum(S, 7) O(log n) 1 3 -1 4 1 1 1 3 3 4 1 9 1 3 -1 4 1 1 T: 1 3 3 4 1 9 Sum(S, i) Sum(S, 7) int sum(int idx) { int sum = 0; while (idx > 0) { sum += T[idx]; idx -= (idx & -idx); } return sum; sum: 8 idx: 0 (0000) O(log n)
Get(S, i) Get(S, i): Sum(S, i) - Sum(S, i-1) Keep a reference to A int get(int idx) { int sum = T[idx]; if (idx > 0) { int z = idx - (idx & -idx); idx--; while (idx != z) { sum -= tree[idx]; idx -= (idx & -idx); } return sum; O(log n)
Update(S, i,v) 1 3 9 3 4 1 A: 1 3 -1 4 1 4 3 3 7 8 9
Update(S, i,v) 1 3 9 3 4 1 A: 1 3 -1 2 4 1 4 3 5 9 10 11
Update(S, i,v) 1 3 9 3 2 4 1 A: 1 3 -1 2 4 1 4 3 5 9 10 11
Update(S, i,v) 1 3 9 3 2 6 1 A: 1 3 -1 2 4 1 4 3 5 9 10 11
Update(S, i,v) A: But how should we encode the index? 1 3 -1 2 4 1 4 3 1 3 11 3 2 6 But how should we encode the index? 1 A: 1 3 -1 2 4 1 4 3 5 9 10 11
Update(S, i, v) And that’s all! Update(S, i, v) O(log n) void update(int idx ,int val) { while (idx < |T|) { T[idx] += val; idx += (idx & -idx); } O(log n) And that’s all!
Extensions O( 2 𝑑 log 𝑑 𝑛 ) Operations for scaling all values Operations for finding the index of a particular sum Multidimensional Binary Indexed Trees O( 2 𝑑 log 𝑑 𝑛 ) void update(int idx ,int val) { while (idx <= MAX_VAL) { T[idx] += val; idx += (idx & -idx); }
Extensions O( 2 𝑑 log 𝑑 𝑛 ) Operations for scaling all values Operations for finding the index of a particular sum Multidimensional Binary Indexed Trees O( 2 𝑑 log 𝑑 𝑛 ) void updatey(int x, int y, int val) { while (y <= MAX_Y) { T[x][y] += val; y += (y& -y); } void update(int x, int y, int val) { while (x <= MAX_X) { updatey(x,y,val); x += (x & -x); }
Problems EAPC10I – Imagine BAPC14 – Excellent Engineers …
EAPC10I A square board of 1024x1024 square cm Stickers of 1x1 of party A and B in alternating pattern A B A B B A B A B Query: how many stickers of each party in (x1,y1,x2,y2)? Update: a sticker for party A or B was placed at (x,y)
Solution Using a 2-dimensional Binary Indexed Tree How do we store stickers? We keep track of the sum of stickers for A Stickers for B = total - #A How do we query a rectangle (x1,y1,x2,y2)? Sum(x1,y1,x2,y2) = Sum(x2, y2) - Sum(x1-1, y2) - Sum(x2, y -1) + Sum(x1-1, y1-1)
Questions?