Data structure for inverting a subarray in log(n)

主宰稳场 提交于 2020-01-05 03:34:43

问题


Build a Data structure that has functions:

set(arr,n) - initialize the structure with array arr of length n. Time O(n)

fetch(i) - fetch arr[i]. Time O(log(n))

invert(k,j) - (when 0 <= k <= j <= n) inverts the sub-array [k,j]. meaning [4,7,2,8,5,4] with invert(2,5) becomes [4,7,4,5,8,2]. Time O(log(n))

How about saving the indices in binary search tree and using a flag saying the index is inverted? But if I do more than 1 invert, it mess it up.


回答1:


Here is how we can approach designing such a data structure. Indeed, using a balanced binary search tree is a good idea to start.

First, let us store array elements as pairs (index, value). Naturally, the elements are sorted by index, so that the in-order traversal of a tree will yield the array in its original order.

Now, if we maintain a balanced binary search tree, and store the size of the subtree in each node, we can already do fetch in O(log n).

Next, let us only pretend we store the index. Instead, we still arrange elements as we did with (index, value) pairs, but store only the value. The index is now stored implicitly and can be calculated as follows. Start from the root and go down to the target node. Whenever we move to a left subtree, the index does not change. When moving to a right subtree, add the size of the left subtree plus one (the size of the current vertex) to the index.

What we got at this point is a fixed-length array stored in a balanced binary search tree. It takes O(log n) to access (read or write) any element, as opposed to O(1) for a plain fixed-length array, so it is about time to get some benefit for all the trouble.

The next step is to devise a way to split our array into left and right parts in O(log n) given the required size of the left part, and merge two arrays by concatenation. This step introduces dependency on our choice of the balanced binary search tree. Treap is the obvious candidate since it is built on top of the split and merge primitives, so this improvement comes for free. Perhaps it is also possible to split a Red-black tree or a Splay tree in O(log n) (though I admit I didn't try to figure out the details myself).

Right now, the structure is already more powerful than an array: it allows splitting and concatenation of "arrays" in O(log n), although element access is as slow as O(log n) too. Note that this would not be possible if we still stored index explicitly at this point, since indices would be broken in the right part of a split or merge operation.

Finally, it is time to introduce the invert operation. Let us store a flag in each node to signal whether the whole subtree of this node has to be inverted. This flag will be lazily propagating: whenever we access a node, before doing anything, check if the flag is true. If this is the case, swap the left and right subtrees, toggle (true <-> false) the flag in the root nodes of both subtrees, and set the flag in the current node to false.

Now, when we want to invert a subarray:

  • split the array into three parts (before the subarray, the subarray itself, and after the subarray) by two split operations,
  • toggle (true <-> false) the flag in the root of the middle (subarray) part,
  • then merge the three parts back in their original order by two merge operations.


来源:https://stackoverflow.com/questions/37236176/data-structure-for-inverting-a-subarray-in-logn

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!