Range queries and Fenwick Trees Version 1.1 Yaseen Mowzer 2nd IOI - - PowerPoint PPT Presentation

range queries and fenwick trees
SMART_READER_LITE
LIVE PREVIEW

Range queries and Fenwick Trees Version 1.1 Yaseen Mowzer 2nd IOI - - PowerPoint PPT Presentation

Range queries and Fenwick Trees Version 1.1 Yaseen Mowzer 2nd IOI Training Camp 2017 (3 February 2018) Preliminaries All ranges will be half open ranges e [ a , b ) a e < b Occasionally 1 is a more convenient starting


slide-1
SLIDE 1

Range queries and Fenwick Trees

Version 1.1 Yaseen Mowzer 2nd IOI Training Camp 2017 (3 February 2018)

slide-2
SLIDE 2

Preliminaries

◮ All ranges will be half open ranges e ∈ [a, b) ⇐

⇒ a ≤ e < b

◮ Occasionally 1 is a more convenient starting index than 0

slide-3
SLIDE 3

Susie has questions

Problem

Susie has 1 < N < 106 model ships arranged in a sequence numbered 0, . . . , N − 1. The ith boat has a size of si (1 < si < 109). At any given time Susie may replace a boat with another boat of a different size. Given two integers a and b, report the sizes of all the ships between a and b.

slide-4
SLIDE 4

Susie has questions

Problem

Susie has 1 < N < 106 model ships arranged in a sequence numbered 0, . . . , N − 1. The ith boat has a size of si (1 < si < 109). At any given time Susie may replace a boat with another boat of a different size. Given two integers a and b, report the sizes of all the ships between a and b. In summary

◮ ∼ 106 model ships of different sizes ∼ 109. ◮ Susie can change the size of a ship. ◮ Report all sizes of ships between a and b.

slide-5
SLIDE 5

Susie’s questions are easy to answer

Solution

Store an array of all the ships. Time Complexity

◮ Let m = b − a. m is the width of the query. ◮ O(N) construction ◮ O(m) query ◮ O(1) update

slide-6
SLIDE 6

Susie wants the size of the smallest ship

Problem

Susie also wants to know the minimum of all the ship sizes between a and b.

slide-7
SLIDE 7

Susie wants the size of the smallest ship

Problem

Susie also wants to know the minimum of all the ship sizes between a and b. Observations

◮ The min function is associative i.e.

min(a, min(b, c)) = min(min(a, b), c)

◮ In other words, min function forms a semigroup with the

integers

slide-8
SLIDE 8

Susie wants the size of the smallest ship

Problem

Susie also wants to know the minimum of all the ship sizes between a and b. Observations

◮ The min function is associative i.e.

min(a, min(b, c)) = min(min(a, b), c)

◮ In other words, min function forms a semigroup with the

integers

◮ It is unnecessary to iterate over m since

min(x1, x2, . . . , x2n) = min(min(x1, . . . , xn), min(xn+1, . . . , x2n)) allows us to “cache” queries.

◮ We can query in better than O(m) time.

slide-9
SLIDE 9

Segment tree

◮ Perfectly balanced binary tree. ◮ The leaf nodes correspond with si. ◮ A parent is the minimum of it’s children.

slide-10
SLIDE 10

Segment tree

◮ Perfectly balanced binary tree. ◮ The leaf nodes correspond with si. ◮ A parent is the minimum of it’s children.

2 5 5 5 17 15 15 20 2 9 9 14 2 2 17

slide-11
SLIDE 11

Representing a Perfectly Balanced Binary Tree

◮ Represent the tree as an array indexed from 1 ◮ For every index i the

◮ left child is 2i ◮ right child is 2i + 1

2 5 5 5 17 15 15 20 2 9 9 14 2 2 17

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

slide-12
SLIDE 12

Update by walking up the tree

def update(index , value ): index += N seg_tree[index] = value index /= 2 while index > 0: seg_tree[index] = min( seg_tree [2 * index], seg_tree [2 * index + 1] ) index /= 2

slide-13
SLIDE 13

Query by walking up the tree

def query(a, b): a += N b += N ans = ∞ while a < b: if a % 2 == 1: ans = min(seg_tree[a], ans) a += 1 if (b - 1) % 2 == 0: ans = min(seg_tree[b - 1], ans) a /= 2 b /= 2

slide-14
SLIDE 14

Time complexity

◮ O(N) construction ◮ O(log N) updates ◮ O(log N) query

slide-15
SLIDE 15

Susie updates ranges

Problem

Susie can replaces all ships between a and b with many ships of the same size.

slide-16
SLIDE 16

Susie updates ranges

Problem

Susie can replaces all ships between a and b with many ships of the same size.

Solution

When updating a range, if a node is completely within the range, mark it as overridden and don’t update the children.

slide-17
SLIDE 17

Update code

def rec_update (i, l, r, v): a = segment_start (i) b = segment_end (i) if l <= a and b <= r: # Completely contained in the interval

  • veride[i] = True

seg_tree[i] = v elif l < b and a < r: # Intersects , thus update children push_down_overide (i) rec_update (2 * i, l, r, v) rec_update (2 * i + 1, l, r, v) seg_tree[i] = min(seg_tree [2 * i], seg_tree [2 * i + 1]) def push_down_overide (i): l = 2 * i r = l + 1 if

  • veride[i]:
  • veride[i] = False
  • veride[l] = overide[r] = True

seg_tree[l] = seg_tree[r] = seg_tree[i]

slide-18
SLIDE 18

Query

def query(i, l, r): a = segment_start (i) b = segment_end (i) if l <= a and b <= r: # Completely contained in the interval return seg_tree[i] elif b <= l or r <= a: # Don ’t intersect do nothing return ∞ # Return identity else: push_down_overide (i) return min(query (2 * i, l, r), query (2 * i + 1, l, r))

slide-19
SLIDE 19

Susie asks for the sum

Problem

Find the sum of the sizes of the boats between a and b. (Only updating single points at a time).

slide-20
SLIDE 20

Susie asks for the sum

Problem

Find the sum of the sizes of the boats between a and b. (Only updating single points at a time). Observation

◮ Addition has an identity (0) ◮ and an inverse operation (−) ◮ Addition forms a group with the integers

slide-21
SLIDE 21

Susie asks for the sum

Problem

Find the sum of the sizes of the boats between a and b. (Only updating single points at a time). Observation

◮ Addition has an identity (0) ◮ and an inverse operation (−) ◮ Addition forms a group with the integers

We can subtract!

slide-22
SLIDE 22

Prefix sums

prefix_sum = [0] for i in range(N): prefix_sum.append(ships[i] + prefix_sum [ -1]) def query(l, r): return prefix_sum[r] - prefix_sum[l] “Subtraction” is required

slide-23
SLIDE 23

Prefix sums

prefix_sum = [0] for i in range(N): prefix_sum.append(ships[i] + prefix_sum [ -1]) def query(l, r): return prefix_sum[r] - prefix_sum[l] “Subtraction” is required Time Complexity

◮ O(N) construction ◮ O(1) query ◮ O(N) update

Update is too slow!

slide-24
SLIDE 24

Fenwick trees

Ideas

◮ We can use a segment tree, but we can do better

slide-25
SLIDE 25

Combine the prefix sum with the segment tree

109 67 42 32 35 23 19 15 17 15 20 9 14 2 17

slide-26
SLIDE 26

Right nodes are redundant

109 67 42 = 109 − 67 32 35 = 67 − 32 23 19 = 42 − 23 15 17 = 32 − 15 15 20 = 35 − 15 9 14 = 23 − 9 2 17 = 19 − 2

slide-27
SLIDE 27

Chop off the right nodes

109 67 32 23 15 15 9 2

slide-28
SLIDE 28

Chop off the right nodes

109 67 32 23 15 15 9 2 15 32 15 67 9 23 2 109

slide-29
SLIDE 29

We are left with N numbers

109

1000

67

0100

32

0010

23

0110

15 0001 15 0011 9

0101

2

0111

15 32 15 67 9 23 2 109

slide-30
SLIDE 30

Storage

◮ We only have N nodes (not 2N) ◮ We use an array indexed from 1. ◮ Let s be the greatest power of 2 that divides i ◮ Index i contains the sum of [i − r + 1, i + 1)

slide-31
SLIDE 31

Updating

◮ We update by increasing rather than setting. ◮ It is easy to compute what to increase ◮ i is the smallest index that contains si ◮ i + r is the next element that contains i

slide-32
SLIDE 32

Computing r

We can compute the largest power of two by using i & ~(i - 1) 10101000

  • 1
  • ~

10100111

  • 01011000

& 10101000

  • 00001000
slide-33
SLIDE 33

Code for fenwick tree

def update(i, v): while i < N: fenwick_tree [i] += v # Go to parent i += (i & ~(i - 1)) def query(i): acc = 0 # Identity while i > 0: acc += fenwick_tree [i] # Go to previous i -= (i & ~(i - 1)) query(a, b) = query(b) - query(a)

slide-34
SLIDE 34

Problem

Susie can also increase the size of the boats from a to b by v, but will only ask for the size of one boat.

slide-35
SLIDE 35

Problem

Susie can also increase the size of the boats from a to b by v, but will only ask for the size of one boat. We can apply a tranformation.

◮ di = si − si−1 ◮ d0 = s0

Construct a fenwick tree over d

◮ We can query a point just by querying query(point) ◮ Update a range by update(a, v) and update(b, -v)

slide-36
SLIDE 36

Problem

Susie can also increase the size of the boats from a to b by v, but will only ask for the size of one boat. We can apply a tranformation.

◮ di = si − si−1 ◮ d0 = s0

Construct a fenwick tree over d

◮ We can query a point just by querying query(point) ◮ Update a range by update(a, v) and update(b, -v) ◮ Beware of off-by-one errors

slide-37
SLIDE 37

Susie wants to query a range

a−1

  • i=0

si =

a−1

  • i=0

i

  • j

dj =

a−1

  • i=0

(a − i)dj = a a−1

  • i=0

di

a−1

  • i=0

idi

  • Make a Fenwick tree with idi as well.
slide-38
SLIDE 38

Better solution

Use a segment tree instead 109 67 32 15 17 35 15 20 42 23 9 14 19 2 17