CPSC 490: Problem Solving in Computer Science 1 Range-minimum query - - PowerPoint PPT Presentation

cpsc 490 problem solving in computer science
SMART_READER_LITE
LIVE PREVIEW

CPSC 490: Problem Solving in Computer Science 1 Range-minimum query - - PowerPoint PPT Presentation

Lecture 11: Binary jumping, Digit DP Henry Xia, Brandon Zhang based on CPSC 490 slides from 2014-2018 2019-02-07 University of British Columbia CPSC 490: Problem Solving in Computer Science 1 Range-minimum query Given an array A of N 10 6


slide-1
SLIDE 1

CPSC 490: Problem Solving in Computer Science

Lecture 11: Binary jumping, Digit DP

Henry Xia, Brandon Zhang

based on CPSC 490 slides from 2014-2018

2019-02-07

University of British Columbia

slide-2
SLIDE 2

Range-minimum query

Given an array A of N ≤ 106 numbers, answer Q ≤ 106 queries of the form “What is the minimum number in the subarray A[l..r]?”

1

slide-3
SLIDE 3

Range-minimum query

Naive solution: O(NQ). Too slow! Let’s try doing some computations to help us out. We need to “jump” by a lot when computing the min, if we want to do it fast. Let’s jump by powers of 2!

2

slide-4
SLIDE 4

Range-minimum query

Naive solution: O(NQ). Too slow! Let’s try doing some computations to help us out. We need to “jump” by a lot when computing the min, if we want to do it fast. Let’s jump by powers of 2!

2

slide-5
SLIDE 5

Binary jumping

f(i, p) = the minimum number in A[i..i + 2p − 1]. Base case: f(i, 0) = A[i]. Recursive case: f(i, p) = { min{f(i, p − 1), f(i + 2p, p − 1)} i + 2p < n f(i, p − 1)

  • therwise

Computing this table takes O(N log N). How do we handle queries? If we need to find the minimum element of A l r , let q be the largest integer such that 2q r l

  • 1. The answer is

f l q f r 2q 1 q . O 1 per query!

3

slide-6
SLIDE 6

Binary jumping

f(i, p) = the minimum number in A[i..i + 2p − 1]. Base case: f(i, 0) = A[i]. Recursive case: f(i, p) = { min{f(i, p − 1), f(i + 2p, p − 1)} i + 2p < n f(i, p − 1)

  • therwise

Computing this table takes O(N log N). How do we handle queries? If we need to find the minimum element of A[l..r], let q be the largest integer such that 2q ≤ r − l + 1. The answer is min{f(l, q), f(r − 2q + 1, q)}. O(1) per query!

3

slide-7
SLIDE 7

Lowest common ancestor

Given a tree with N ≤ 105 nodes, how can we answer Q ≤ 105 queries of the form “What is the lowest common ancestor of nodes u and v”?

4

slide-8
SLIDE 8

Lowest common ancestor

There are many ways to do this, but this binary jumping-based solution generalizes well to many problems! We’ll store depth(u) = number of nodes on the path to the root, and par(u, k) = the 2kth ancestor of u (2kth node on the path from u to the root). First, let’s figure out how to compute these: depth(root) = 0, depth(u) = depth(parent(u)) + 1 par(u, 0) = parent(u), par(u, k) = par(par(u, k − 1), k − 1)

5

slide-9
SLIDE 9

Lowest common ancestor

Given this information depth(u) = # of nodes on the path to the root par(u, k) = the 2kth ancestor of u how do we compute the LCA of u and v?

  • Move up the deeper node: if u is deeper, then iteratively replace u ← par(u, k) for

the largest k so that we don’t jump up above v.

  • At this point, if u = v then we’re done.
  • Otherwise, jump up to the LCA: now that u and v are at equal depth, iteratively

replace u ← par(u, k), v ← par(v, k) for the largest k such that par(u, k) ̸= par(v, k).

  • The LCA is parent(u) (= parent(v)).

Runtime: O(log N) per query.

6

slide-10
SLIDE 10

Lowest common ancestor

1

def lca(u, v):

2

if depth[u] < depth[v]:

3

swap u and v

4

for k = log N .. 0:

5

if depth[u] - 2k >= depth[v]:

6

u = par[u][k]

7

if u == v:

8

return u

9

for k = log N .. 0:

10

if par[u][k] != par[v][k]:

11

u = par[u][k], v = par[v][k]

12

return par[u][0]

7

slide-11
SLIDE 11

Lowest common ancestor

Why consider LCA at all? If we want the path from u to v, it is exactly the path u ↗ lca(u, v) ↘ v. We can answer many difgerent kinds of path queries using this technique!

8

slide-12
SLIDE 12

Problem 1 – Path lengths

Input: a tree with N ≤ 105 nodes. Output: answer Q ≤ 105 queries of the form “What is the length of the path between u and v?”

9

slide-13
SLIDE 13

Problem 1 – Solution

Binary jumping! DP states:

  • par(u, k) = 2kth ancestor of u
  • dist(u, k) = length of the path between u and its 2kth ancestor

Recurrence:

  • par(u, k): same as before (par(u, 0) = parent(u), par(u, k) = par(par(u, k − 1), k − 1))
  • dist(u, 0) = c(u, parent(u)), dist(u, k) = dist(u, k − 1) + dist(par(u, k − 1), k − 1)

Answer: whenever we make a jump in our LCA-finding algorithm, also add the corresponding dist value to the total path length. Time complexity: O((N + Q) log N)

10

slide-14
SLIDE 14

Problem 2 – Maximum bandwidth, revisited

Recall the maximum bandwidth problem: given a graph on N ≤ 105 nodes and M ≤ 105 edges, find the path from u to v such that the minimum edge weight is maximized. Now, answer Q ≤ 105 queries of this form!

11

slide-15
SLIDE 15

Problem 2 – Solution

Remember that to solve this problem, we found the MST and used paths on that tree. Use binary jumping on this tree, similarly to the last problem! Time complexity: O(M log M + (N + Q) log N)

12

slide-16
SLIDE 16

Problem 3 – Path counting

Input: a tree on N ≤ 105 nodes, and M ≤ 105 special paths on the tree between ui and vi. Output: the node that is on the maximum number of special paths.

Source: USACO Platinum December 2015

13

slide-17
SLIDE 17

Problem 3 – Solution

First, let’s consider the case where the tree is a stick. Store a value at each node which is the number of special paths it’s on. For a special u-v-path, let’s add 1 to each of the nodes on the path between u and v, then get the node with the maximum value. But this is too slow... Observation: we can “accumulate” values from bottom to top.

  • Store an extra amount at each node u which will be the amount the value changes

from the child(u) to u.

  • For a u-v-path (assuming u is deeper), add +1 to u’s amount and add −1 to

parent(v)’s amount.

  • The value at a node u is then value(child(w)) + amount(w).

14

slide-18
SLIDE 18

Problem 3 – Solution

Now for a general tree...

  • Our paths now go u ↗ lca(u, v) ↘ v. Split this into two paths u → lca(u, v),

v → lca(u, v).

  • Add +1 to u’s amount and v’s amount, add −1 to lca(u, v)’s amount, and add −1 to

parent(lca(u, v))’s amount.

  • Do the same accumulation, going from the deepest nodes to the root.

Time complexity: O((N + M) log N)

15

slide-19
SLIDE 19

Digit DP

We’ll answer the question “Count the number of integers 0 ≤ x ≤ N such that x satisfies some property”. N may be very large (say, up to 10100). As an example, let’s answer the trivial question “Count the number of integers 0 ≤ x ≤ N” using a DP. DP idea: we’ll build numbers satisfying the conditions digit by digit.

16

slide-20
SLIDE 20

Counting numbers

DP state: f(digit, less) = # of ways to choose the digits digit, digit + 1, . . . , (# of digits) of x such that 0 ≤ x ≤ N. less is 1 if we chose the first few digits of x so that it’ll be strictly less than N. Otherwise (if less is 0), the first digits of x match the first digits of N. Base case: f

  • f digits

1 less 1. For the recursive case, try placing all possible digits at the current position and update less accordingly. f digit less

9 i 0 f digit

1 1 less 1 f digit 1 0

N digit 1 i

f digit 1 1 less Answer: f 0 0 . Time complexity: O digits .

17

slide-21
SLIDE 21

Counting numbers

DP state: f(digit, less) = # of ways to choose the digits digit, digit + 1, . . . , (# of digits) of x such that 0 ≤ x ≤ N. less is 1 if we chose the first few digits of x so that it’ll be strictly less than N. Otherwise (if less is 0), the first digits of x match the first digits of N. Base case: f(# of digits + 1, less) = 1. For the recursive case, try placing all possible digits at the current position and update less accordingly. f(digit, less) = {∑9

i=0 f(digit + 1, 1)

less = 1 f(digit + 1, 0) + ∑N[digit]−1

i=0

f(digit + 1, 1) less = 0 Answer: f 0 0 . Time complexity: O digits .

17

slide-22
SLIDE 22

Counting numbers

DP state: f(digit, less) = # of ways to choose the digits digit, digit + 1, . . . , (# of digits) of x such that 0 ≤ x ≤ N. less is 1 if we chose the first few digits of x so that it’ll be strictly less than N. Otherwise (if less is 0), the first digits of x match the first digits of N. Base case: f(# of digits + 1, less) = 1. For the recursive case, try placing all possible digits at the current position and update less accordingly. f(digit, less) = {∑9

i=0 f(digit + 1, 1)

less = 1 f(digit + 1, 0) + ∑N[digit]−1

i=0

f(digit + 1, 1) less = 0 Answer: f(0, 0). Time complexity: O(# digits).

17

slide-23
SLIDE 23

Problem 4 – Digit counting

Given N ≤ 10100, count the integers 0 ≤ x ≤ N where the digit d ̸= 0 appears exactly k times.

18

slide-24
SLIDE 24

Problem 4 – Solution

DP state: f(digit, less, count) where digit and less are the same as before, and count is the number of digits we’ve already set that are equal to d. Base case: f

  • f digits

1 less i k 0, f

  • f digits

1 less k 1. Recurrence: same as before, but add 1 to count if we put the digit d in the current position. Answer: f 0 0 0 . Time complexity: O digits 2 .

19

slide-25
SLIDE 25

Problem 4 – Solution

DP state: f(digit, less, count) where digit and less are the same as before, and count is the number of digits we’ve already set that are equal to d. Base case: f(# of digits + 1, less, i ̸= k) = 0, f(# of digits + 1, less, k) = 1. Recurrence: same as before, but add 1 to count if we put the digit d in the current position. Answer: f 0 0 0 . Time complexity: O digits 2 .

19

slide-26
SLIDE 26

Problem 4 – Solution

DP state: f(digit, less, count) where digit and less are the same as before, and count is the number of digits we’ve already set that are equal to d. Base case: f(# of digits + 1, less, i ̸= k) = 0, f(# of digits + 1, less, k) = 1. Recurrence: same as before, but add 1 to count if we put the digit d in the current position. Answer: f(0, 0, 0). Time complexity: O((# digits)2).

19

slide-27
SLIDE 27

Problem 5 – Digit counting 2

Given l ≤ r ≤ 10100, count the integers l ≤ x ≤ r where the digit d ̸= 0 appears exactly k times.

20

slide-28
SLIDE 28

Problem 5 – Solution

Let a(n) = # of integers 0 ≤ x ≤ n where the digit d ̸= 0 appears exactly k times. (We solved this in the last problem.) Then the answer is just a(r) − a(l − 1)! Time complexity: the same

21

slide-29
SLIDE 29

Problem 6 – Digit counting 3

Given l ≤ r ≤ 10100, count the integers l ≤ x ≤ r where the digit d ̸= 0 appears exactly k times and x is a multiple of m (where 1 ≤ m ≤ 100).

22

slide-30
SLIDE 30

Problem 6 – Solution

Just add more state to keep track of all the things we need to remember! We’ll also remember rem = the current remainder of x modulo m. In our recurrence, we’ll also update the new remainder, and our base case is 1 only when the remainder is 0. Time complexity: O(m(#digits)2)

23