Implicit Treap

Maintains a dynamic sequence with an implicit Treap whose balancing priorities are randomized.

It supports insertion and erasure by position, element access and replacement, range reversal, and range products.

General form

proc op(
    left,
    right: S,
): S =
  ...

proc e(): S =
  ...

type
  Treap =
    ImplicitTreapType[S](
      op,
      e,
    )

var tree =
  Treap.init(
    values,
  )

An empty tree can be initialized as follows.

var tree =
  Treap.init()

Parameters and types

op must be associative, and e() must be both a left and right identity. Commutativity is not required.

The default seed is DefaultImplicitTreapSeed. It is fixed, so the same operation sequence creates a reproducible tree. The seed affects only the tree shape and running time; it does not affect returned values or correctness.

When an initial sequence is supplied, node storage is preallocated for its length. Storage belonging to erased nodes is reused by later insertions.

Preconditions

Let n = tree.len.

A violation raises ValueError.

Return values and side effects

prod on an empty range returns e().

Every subtree stores both its forward and backward aggregate. Therefore range reversal works for noncommutative Monoids without an extra callback for reversing an aggregate.

Example

import atcoder/extra/structure/implicit_treapproc op(    left,    right: int,): int =  left + rightproc e(): int =  0type  SumTreap =    ImplicitTreapType[int](      op,      e,    )var tree =  SumTreap.init(    @[1, 2, 3, 4]  )tree.insert(  2,  10,)doAssert tree.toSeq() ==  @[1, 2, 10, 3, 4]tree.reverse(  1,  4,)doAssert tree.toSeq() ==  @[1, 3, 10, 2, 4]doAssert tree.prod(  1,  4,) == 15

This Implicit Treap is an owning container. Internal nodes and the root are not exposed; split and merge are implementation details.

The first public version supports reversal and Monoid products, but does not include Lazy Actions.

Complexity and implementation

Let n be the current length.

Expected complexity:

The worst case is O(n) when the randomized tree becomes highly unbalanced.

Memory usage is O(n). Erased node slots are reused through a free list.