Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Fenwick tree

A Binary Indexed Tree: prefix sums and point updates both in O(log n), demoing the p/moul/x/daily/fenwick library.

The values

3, 1, 4, 1, 5, 9, 2, 6 — 8 slots totalling 31.

Prefix sums

i value Prefix(i+1)
0 3 3
1 1 4
2 4 8
3 1 9
4 5 14
5 9 23
6 2 25
7 6 31

Range queries

call meaning result
Range(2, 5) slots 2, 3, 4 10
Range(0, 8) everything 31
Range(5, 5) empty 0
Range(-9, 99) clamped to the ends 31

Reads clamp instead of panicking. A realm cannot be redeployed on the same path, so a Render that panics on an out-of-range index is a page that is broken for good. Writes do panic: a bad Add is a transaction, and aborting it is the useful answer.

What the tree actually stores

The array is not a copy of the values. Each internal slot holds the sum of a run of them, and the run lengths are the powers of two in the index. That is the whole trick, and Covers makes it visible.

node covers slots sum
1 [0, 1) 3
2 [0, 2) 4
3 [2, 3) 4
4 [0, 4) 9
5 [4, 5) 5
6 [4, 6) 14
7 [6, 7) 2
8 [0, 8) 31

A prefix walk visits one node per set bit of the index, and those nodes tile the prefix exactly: no gap, no overlap. Eight slots means at most three nodes per query.

The weighted draw

SearchPrefix(target) names the slot that owns a target drawn below Total, in O(log n). Each holder is picked in proportion to their stake, and a zero stake can never be picked at all.

holder stake owns targets share
alice 30 [0, 30) 30%
bob 0 none 0%
carol 45 [30, 75) 45%
dave 5 [75, 80) 5%
erin 20 [80, 100) 20%
target SearchPrefix holder
0 0 alice
29 0 alice
30 2 carol
74 2 carol
99 4 erin

Note target 30: it is the first one past alice's share, and it skips bob entirely rather than landing on a holder with nothing staked. The search steps over zero-weight slots because their prefix does not advance, not because anything checks for them.

Why not a plain slice

Two obvious implementations each win one column and lose another. A realm whose scoreboard is written by every player and read by every page view pays both costs, which is where the middle row earns its keep.

structure point update prefix sum weighted draw
plain slice O(1) O(n) O(n)
Fenwick tree O(log n) O(log n) O(log n)
running totals O(n) O(1) O(log n)

The tree also carries no storage overhead: it is exactly n values, rearranged.