Editorial for Facebook Hacker Cup '19 Final Round P6 - Temporal Revision
Submitting an official solution before solving the problem yourself is a bannable offence.
We'll begin by considering the set of meaningfully different states which the Enterprise can be in, specifically in terms of which graph nodes (planets) it may visit. Before hour , all nodes form a single connected component, and the Enterprise may travel freely between them. Then, each time a type-1 event causes nodes and to no longer be reachable from one another, the component they were both part of becomes split into two, such that if the Enterprise was in that component at hour , it must henceforth choose to be in one of the two resulting components. This suggests a binary tree structure of state nodes, each of which corresponds to a component and a time interval for which that component exists.
If we iterate over the events in reverse while maintaining a disjoint-set data structure of components (initialized with all components which exist after hour ), we can reconstruct this implicit binary tree in time. Each time a type-1 event causes two different components to merge together, their corresponding tree nodes should be the children of a new tree node corresponding to the combined component.
It is then feasible to consider some dynamic programming on this tree, ignoring the ability to travel back in time for now. Let's initially consider the basic question: "what's the maximum number of geyser activations which the Enterprise can be present for if it begins in tree node at that node's earliest time?". Letting this value be , we have . Let's next consider a more complex and useful question: "what's the maximum number of geysers from which the Enterprise can collect neurozine if it begins in tree node at time ?". This is equal to . So far, these are all relatively simple values which we can precompute while constructing the tree (still in time) and then evaluate in time (due to binary searching through geyser deactivation times). To wrap this up into the ability to answer a query (still ignoring traveling back in time), all that remains is efficiently computing the tree node corresponding to a given node at a given time , which is doable in time if we begin at the leaf tree node corresponding to and then binary search up a skip-list of that tree node's ancestors (which can be precomputed throughout the tree in time).
We're ready to add in some time travel — what if you may only travel back to the original time ? This may be thought of as the Enterprise's path downwards through the tree being allowed to branch off at most once. As such, we can add an extra flag to our DP (), and then evaluate a similar expression to before (with this time).
Finally, we'll add in the ability to travel back to time (noting that there's no benefit to travelling to later than that). One possibility is that the Enterprise will pass through tree node again after going back in time, and branch off later — in this case, we'll have plus the number of other active geysers which the Enterprise had access to between times and , which are possible (though not trivial) to count in time using the same precomputed values as described above. The other possibility is that the Enterprise will branch off at an earlier point (from one of the ancestors of tree node ) — for each such possible ancestor , we'll have , plus , plus the number of other active geysers which the Enterprise had access to between times and the end of tree node (which are similarly possible to count along the way). The query's answer is then the maximum of values obtained from any of these possibilities, and we have a solution with time complexity .
Comments