guest@itl:~/home/data-structures$
templates/splay-tree.cpp
compilable
$cat templates/splay-tree

Splay Tree

Self-adjusting BST with O(log n) amortized operations via splay rotations.

#splay-tree#bst#self-adjusting#order-statistics
Log in to track progress, save custom versions, and organize into collections.Log In
$cat source_code/
cpp
#include <bits/stdc++.h>
using namespace std;

struct SplayTree {
    struct Node {
        Node *ch[2], *par;
        int val, sz, freq;
        Node() : sz(0), freq(0) { par = ch[0] = ch[1] = this; val = INT_MIN; }
        Node(int v) : val(v), sz(1), freq(1) { par = ch[0] = ch[1] = EMPTY; }
        void pull() { sz = freq + ch[0]->sz + ch[1]->sz; }
    };

    static Node* EMPTY;
    Node* root;

    SplayTree() : root(EMPTY) {}

    void link(Node* p, Node* c, int d) {
        if (p != EMPTY) { p->ch[d] = c; p->pull(); }
        if (c != EMPTY) c->par = p;
    }

    int dir(Node* p, Node* c) { return p->ch[1] == c; }

    void rotate(Node* p, int d) {
        Node* q = p->ch[d], *g = p->par;
        link(p, q->ch[!d], d);
        link(q, p, !d);
        link(g, q, dir(g, p));
    }

    void splay(Node* q) {
        while (q->par != EMPTY) {
            Node* p = q->par, *g = p->par;
            int d1 = dir(p, q), d2 = dir(g, p);
            if (g == EMPTY) rotate(p, d1);
            else if (d1 == d2) { rotate(g, d2); rotate(p, d1); }
            else { rotate(p, d1); rotate(g, d2); }
        }
        root = q;
    }

    Node* find(Node* p, int val) {
        if (p == EMPTY) return EMPTY;
        Node* c = p->ch[val > p->val];
        if (p->val == val || c == EMPTY) return p;
        return find(c, val);
    }

    void insert(int val) {
        if (root == EMPTY) { root = new Node(val); return; }
        root = find(root, val); splay(root);
        if (root->val == val) { root->freq++; root->sz++; return; }
        Node* q = new Node(val);
        int d = val > root->val;
        if (root->ch[d] != EMPTY) {
            Node* c = root->ch[d];
            link(root, EMPTY, d);
            link(q, c, q->val < c->val);
        }
        link(q, root, val > root->val ? 0 : 1);
        root = q;
    }

    void erase(int val) {
        root = find(root, val); splay(root);
        if (root->val != val) return;
        if (root->freq > 1) { root->freq--; root->sz--; return; }
        Node* l = root->ch[0], *r = root->ch[1];
        delete root;
        if (l != EMPTY) l->par = EMPTY;
        if (r != EMPTY) r->par = EMPTY;
        if (l == EMPTY) { root = r; return; }
        root = find(l, INT_MAX); splay(root);
        link(root, r, 1);
    }

    bool search(int val) {
        root = find(root, val); splay(root);
        return root->val == val;
    }

    int kth(int k) {
        Node* p = root;
        while (p != EMPTY) {
            int ls = p->ch[0]->sz;
            if (k < ls) p = p->ch[0];
            else if (k < ls + p->freq) { splay(p); return p->val; }
            else { k -= ls + p->freq; p = p->ch[1]; }
        }
        return -1;
    }

    int countLess(int val) {
        root = find(root, val); splay(root);
        return root->ch[0]->sz + (root->val < val ? root->freq : 0);
    }

    int size() { return root->sz; }
};

SplayTree::Node* SplayTree::EMPTY = new SplayTree::Node();
102 linesutf-8
$cat explanation_notes.md
notes_viewer --renderedmarkdown (math enabled)

Splay Tree

Self-adjusting BST that moves every accessed node to the root via rotations, giving O(logn)O(\log n) amortized time.

Splay Operation — Three Cases

  • Zig — parent is root → single rotation

  • Zig-zig — node and parent are same-side children → rotate parent first, then node

  • Zig-zag — node and parent are opposite-side children → rotate node twice
  • Operations

  • insert(val) — insert with duplicate counting via freq

  • erase(val) — erase one occurrence (or decrement freq)

  • search(val) — check existence

  • kth(k)kk-th smallest element (0-indexed)

  • countLess(val) — number of elements <val< val

  • split(val) / merge(a, b) — split/merge by value
  • When to Use

  • When you need split/merge on a BST

  • Order-statistics queries

  • Competitive programming problems requiring flexible BST operations
  • Complexity

  • All operations — O(logn)O(\log n) amortized

  • Space — O(n)O(n)