When keys are integers in , word-level tricks beat comparison-based trees. The 64-ary bit tree (“fast set”) gives insert, erase, successor and predecessor in , at most 4 levels for , with words of memory. It’s typically 5-10x faster than std::set.

64-ary bit tree

struct FastSet {
    int n; vector<vector<ull>> s;                  // s[0] = elements, s[h] = non-empty words of level h-1
    FastSet(int n_) : n(n_) { int m = n; do { m = (m + 63) >> 6; s.emplace_back(m); } while (m > 1); }
    bool has(int x) const { return s[0][x >> 6] >> (x & 63) & 1; }
    void insert(int x) { for (auto& v : s) { v[x >> 6] |= 1ULL << (x & 63); x >>= 6; } }
    void erase(int x) { for (auto& v : s) { v[x >> 6] &= ~(1ULL << (x & 63)); if (v[x >> 6]) break; x >>= 6; } }
    int next(int x) const {                        // smallest element >= x, or -1
        if (x < 0) x = 0;
        if (x >= n) return -1;
        for (int h = 0; h < sz(s); h++) {
            if ((x >> 6) >= sz(s[h])) break;
            ull d = s[h][x >> 6] >> (x & 63);
            if (!d) { x = (x >> 6) + 1; continue; }
            x += __builtin_ctzll(d);
            for (int g = h - 1; g >= 0; g--) x = x << 6 | __builtin_ctzll(s[g][x]);
            return x;
        }
        return -1;
    }
    int prev(int x) const {                        // largest element <= x, or -1
        if (x >= n) x = n - 1;
        for (int h = 0; h < sz(s) && x >= 0; h++) {
            ull d = s[h][x >> 6] << (63 - (x & 63));
            if (!d) { x = (x >> 6) - 1; continue; }
            x -= __builtin_clzll(d);
            for (int g = h - 1; g >= 0; g--) x = x << 6 | (63 - __builtin_clzll(s[g][x]));
            return x;
        }
        return -1;
    }
};

Uses: set of alive indices in simulations (“delete , find nearest alive neighbours”), “next free slot”, Dijkstra or BFS with small integer keys (bucket queue over a fast set), sweep lines over compressed coordinates, Mo’s algorithm needing a successor structure with -ish updates.

For “-th smallest” or counts you still need a Fenwick tree over the universe; the fast set only does membership, successor and predecessor.

Other integer structures

StructureOperationsNotes
van Emde Boaspred/succ/insert/delete in recursion (split each key into a high half and low half over ); memory naively, with hashing (a “y-fast trie”-style implementation); beats a balanced BST when is small — gives vs. . In practice a bitset with _Find_next is faster for small universes, and a hash set plus a BIT usually beats both in code length
x-fast / y-fast triepred/succ in binary search over prefix lengths using hash tables of prefixes
fusion treepred in a -tree with branching factor ; each node compares a key against stored keys in via a “sketch and multiply” word trick, beating comparison-based bounds; combined with integer sorting gives sorting — theory, not contest code
bucket queuemonotone priority queue over small keysDial’s algorithm
radix heapmonotone priority queue, Heaps
rank/select bit vector rank and select in bitsbasis of succinct structures below
tango / multi-splay tree-competitive with the optimal offline BST for any access sequencerelevant to the open dynamic optimality conjecture (is a splay tree -competitive? open since 1985)
Brodal queue / hollow heap worst-case insert, meld, find-min, decrease-key; delete-minBrodal (1996) is the theoretical optimum for a meldable priority queue but enormously complicated; the hollow heap (2015) reaches the same amortized bounds far more simply
succinct structures (FM-index, succinct trees)space close to the information-theoretic minimum, still fast queriesFM-index: a compressed full-text index, what DNA aligners use; succinct trees: bits with navigation; genuinely used in bioinformatics and search engines where data doesn’t otherwise fit in memory

In contests the 64-ary bit tree covers what vEB would; the others are worth knowing by name.

Ideas that transfer

  • Word-level parallelism: packing 64 booleans or 8 bytes into a word and operating on them at once is what bitsets, Shift-Or matching, bit-parallel LCS and the fast set all do (Bitset).
  • Four Russians: precompute answers for all small blocks (size ) and combine. That’s the trick behind -preprocessing RMQ (RMQ), boolean matrix multiplication and some LCS speedups.
  • Trading exactness for speed: soft heaps (constant-time operations, some keys corrupted) underpin Chazelle’s MST. Approximate counting and sketches (Count-Min, HyperLogLog) use bounded error to save memory.
  • Retroactive structures support “insert an operation into the past” and see the effect on the present — partially retroactive (query only the present) or fully retroactive (query any point in time). Related to, but stronger than, persistence: persistence lets you read the past, retroactivity lets you change it.
  • Dynamic optimality: whether splay trees are -competitive with every BST is open since 1985. Tango trees achieve -competitiveness.
  • Rank/select and succinct structures (wavelet trees, bits, queries) buy space close to the information-theoretic minimum at a small query-time cost — see the table above.