21-1 Off-line minimum
The off-line minimum problem asks us to maintain a dynamic set of elements from the domain under the operations and . We are given a sequence of and calls, where each key in is inserted exactly once. We wish to determine which key is returned by each call. Specifically, we wish to fill in an array , where for , is the key returned by the th call. The problem is "off-line" in the sense that we are allowed to process the entire sequence before determining any of the returned keys.
a. In the following instance of the off-line minimum problem, each operation is represented by the value of and each is represented by the letter :
Fill in the correct values in the extracted array.
To develop an algorithm for this problem, we break the sequence into homogeneous subsequences. That is, we represent by
where each represents a single call and each represents a (possibly empty) sequence of calls. For each subsequence , we initially place the keys inserted by these operations into a set , which is empty if is empty. We then do the following:
cpp OFF-LINE-MINIMUM(m, n) for i = 1 to n determine j such that i ∈ K[j] if j != m + 1 extracted[j] = i let l be the smallest value greater than j for which set K[l] exists K[l] = K[j] ∪ K[l], destroying K[j] return extracted
b. Argue that the array extracted returned by is correct.
c. Describe how to implement efficiently with a disjoint-set data structure. Give a tight bound on the worst-case running time of your implementation.
a.
b. As we run the for loop, we are picking off the smallest of the possible elements to be removed, knowing for sure that it will be removed by the next unused operation. Then, since that operation is used up, we can pretend that it no longer exists, and combine the set of things that were inserted by that segment with those inserted by the next, since we know that the operation that had separated the two is now used up. Since we proceed to figure out what the various extract operations do one at a time, by the time we are done, we have figured them all out.
c. We let each of the sets be represented by a disjoint set structure. To union them (as on line 6) just call . Checking that they exist is just a matter of keeping track of a linked list of which ones exist(needed for line 5), initially containing all of them, but then, when deleting the set on line 6, we delete it from the linked list that we were maintaining. The only other interaction with the sets that we have to worry about is on line 2, which just amounts to a call of . Since line 2 takes amortized time and we call it exactly times, then, since the rest of the for loop only takes constant time, the total runtime is .