Treap

Overview
Note:
- Cover Advanced Topics if time available
Definition
- tree + heap
- tree for data
- heap for shape
- balanced on average if priority is assigned randomly
Binary Search Tree
- data structure for binaray search
- \(\mathrm{left child < parent < right child \quad \forall nodes}\)
- insert, delete, search for element
- \(O(\text{height})\)
- problem : degenerate(退化)

degenerate BST
- this tree is inserted with in the order of
[5, 6, 7, 8, 9]
- degenerate to linked list, \(O(\text{height}) = O(n)\)

Heap
- \(\mathrm{parent > children \quad \forall nodes}\)

Treap
- a node consists of key and priority
- key : tree
- \(\mathrm{key_{left\ child} < key_{parent} < key_{right\ child} \quad\forall nodes}\)
- priority : heap
- \(\mathrm{priority_{parent} > priority_{children} \quad\forall\ nodes}\)

Balance Property
- Observation : root is inserted before children in BST
- \(\mathrm{priority_{parent} > priority_{children} \quad \forall nodes}\)
- View as a BST whose insertion order is decided by priorities(larger-> earlier)
- why balance?
- priority is given randomly \(\implies\) is balanced on average
Note:
- a single proof for balance property
- insertion is decided by piority, larger priority -> inserted earlier
- emphasize priority decide insertion order if view tree as final tree
- randomized BST
- size as probability weight implementation
- when merge, \(\Pr(a ~\text{as root}) = \frac{\text{size}(a)}{\text{size}(a)+\text{size}(b)}\)
- more
rand()
calls but use less memory
Usage
- Easy to code balanced BST
- Merge / Split operation
- Implicit Treap
- Serve as powerful interval tree(線段樹)
- Free to add additional features!
- Implementation details will be cover later
Note:
- interval tree? segment tree? 名稱緣由
- Should give a sense that treap is strong
- talk about merge/split a little
- details should be cover in implementation
Implicit Treap
- idea : index as key
- blanced array
- text-editor (rope)

Note:
- when implement, record size instead of index
- interval information maintain
Treap as interval tree
- implicit treap with extra information
- interval(subtree) min/max/sum
- interval fold with associative law (結合律)
\(G(S,*)~\text{s.t.}~\forall a, b, c\in S,\ a*b*c\ =\ (a*b)*c\ =\ a*(b*c)\)
- lazy mark (support nterval update)
- more!
- delete interval
- insert interval
Note:
- talk about concept of merge and split
- cover details and code later
Interval Treap

Note:
- Each point is array value itself and record the interval information of its subtree
Implementation
- Merge-split Treap
- Treap Node
- pri, key (or size), val
- (optional) lazy mark
- Basic Operations
- merge, split
- insert, delete (combine merge and split to achieve)
- pull, push (for interval tree)
Note:(can mention a little)
- We use merge-split treap most of the time
- advantages:
- easy to code (~iterval tree)
- more powerful (merge and split supported)
- downsides:
- constant bigger than rotate treap
Treap Node Code
struct Node
{
int pri, key, sz, val;
Node *lc, *rc;
Node(){};
//syntax sugar
Node(int val, int key) :pri(rand()), key(key), sz(1), val(val), mark(0) {};
Node(int val) :pri(rand()), sz(1), val(val), mark(0) {};
}
- hint : without
srand(time(NULL))
sometimes get TLE
- Node means subTreap
Note:
- if no srand, rand() result is predictible by problem setter
- and problem setter can 搞你
- Node in merge-split Treap can be seen as subtree rooted at that Node
Basic Operations
- merge
- merge treap A and treap B
- \(\text{key}_a < \text{key}_b \quad \forall a \in A,\ b \in B\)
- split
- split treap C to treap A and treap B by key value k
- \(\text{key}_a \leqslant k < \text{key}_b \quad \forall a \in A,\ b \in B\)
- inverse operations, both are \(O(\log(n))\) in expectation
- merge + split combinations
Merge
- priority大的當根, 剩下交給子樹處理




- 很清楚的是\(O(\log(n))\)
- 注意到左右永不混雜

Merge
- merge trees rooted at a and b, return merged tree root
- \(\text{key}_a < \text{key}_b \quad \forall a \in A, b \in B\)
- implicit treap?
- No Change, why?
Node* merge(Node* a, Node* b) //key a < key b
{
if (!a) return b; //base case
if (!b) return a;
if(a−>pri > b−>pri)//pri a bigger => a as root
{
a−>r = merge(a−>r, b); //key b bigger => merge b and rc of a
return a;
}
//b as root
b−>l = merge(a, b−>l); //key a smaller => merge a and lc of b
return b;
}
Note:
- Merge preserve BST order, so when still work on implicit key
Split
- split treap C to treap A and treap B by key value k
- 如果當前的根的key \(\leq\) k
- 根及左子樹都屬於A, 右邊再討論
- 遞迴右邊的結果要接回根當前根的右邊






Split
- split treap C to treap A and treap B by key value k
- \(\text{key}_a \leqslant k < \text{key}_b \quad \forall a \in A,\ b \in B\)
- Q : why heap property still holds
void split(Node* c, int k, Node*& a, Node*& b)
{
if (!c) a = b = nullptr; //base case
else if (c−>key <= k)
{ //key of c is smaller than k =>
a = c;
split(c−>r, k, a−>r, b);
}
else
{
b = c;
split(c−>l, k, a, b−>l);
}
}
Note:
- result will store in a, b (passed by reference)
- Answer of Q : because all nodes' children are deeper than themself
- No need to judge priority!!
Split - Implicit Treap
- implicit treap?
- record size and change k while cutting

Note:
Insert
- Insert(C, x)
- Split(C, x, A, B)
- Merge(Merge(A, x), B)
- get AxB
- insert interval?

Note:
- interval(as treap) is nothing special
Delete
- Delete(C, x)
- Split(C, <x, A, B), Split(C, x, D, E)
- Merge(A, E)
- get A(no x)E
- delete interval?…delete "single x"?

Note:
- Answer to delete a single x : D = find(C, x), D = Merge(D->lc, D->rc)
For Interval Treap
- very similar to interval tree
- check validity of information!
- write push and pull function for clarity
- push (down)
- before use subtrees
- 根處理好了剩下「推」給子樹處理
- pull (up)
- when merge subtrees
- 子樹處理好的資訊「拉」上來
Note:
- 叫pull up的時候資訊一定要是對的
- 叫push dpwn的時候自己要處理好
Example (POJ 3580 Super Memo)
void add_(Node *&root, int l, int r, int x)
{
Node *a, *b, *c, *d;
split(root, r, a, b); //a = [1, r]
split(a, l-1, c, d); //d = [l, r]
d->addv += x;
root = merge(merge(c, d), b);
}
Node *merge(Node *a, Node *b) //key a < key b
{
if(!a) return b;
if(!b) return a;
if(a->pri > b->pri)
{
push(a);
a->rc = merge(a->rc, b);
pull(a);
return a;
}
push(b);
b->lc = merge(a, b->lc);
pull(b);
return b;
}
void push(Node *a)
{
if(!a) return;
if(a->rev)
{
swap(a->lc, a->rc);
if(a->lc) a->lc->rev ^= 1;
if(a->rc) a->rc->rev ^= 1;
a->rev = false;
}
if(a->addv != 0)
{
a->val += a->addv;
a->minv += a->addv;
if(a->lc) a->lc->addv += a->addv;
if(a->rc) a->rc->addv += a->addv;
a->addv = 0;
}
return;
}
void pull(Node *a)
{
a->sz = sz(a->lc) + sz(a->rc) + 1;
a->minv = a->val;
//key : push children before pull (maintain inside) or consider addv lazy mark
if(a->lc) a->minv = min(a->minv, a->lc->minv + a->lc->addv);
if(a->rc) a->minv = min(a->minv, a->rc->minv + a->rc->addv);
}
Note:
- From my AC code
- 21277193 maxwill 3580 Accepted 6140K 1532MS G++ 4975B 2020-01-29 13:41:32
PBDS and Rope
- pbds BST : binary search tree
- rope : text editor, implicit BST
- 如果必須實作, ICPC 可以帶模板
但是要夠熟悉賽場上才容易寫得出來變化題
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
#include <ext/rope>
using namespace __gnu_cxx;
typedef tree<int,null_type,less<int>,rb_tree_tag,
tree_order_statistics_node_update> ordered_set;
Note:
- pbds is strong, if only need basic treap op (find kth), pbds/rope is enough
- ICPC 是可以帶模板的, 但是要夠熟悉賽場上才容易寫得出來變化題
- quick introduction and jump to details
pbds BST example
- support find_by_order and order_of_key
ordered_set X;
X.insert(1);
X.insert(2);
X.insert(4);
X.insert(8);
X.insert(16);
cout<<*X.find_by_order(1)<<endl; // 2
cout<<*X.find_by_order(2)<<endl; // 4
cout<<*X.find_by_order(4)<<endl; // 16
cout<<(end(X)==X.find_by_order(6))<<endl; // true
cout<<X.order_of_key(-5)<<endl; // 0
cout<<X.order_of_key(1)<<endl; // 0
cout<<X.order_of_key(3)<<endl; // 2
cout<<X.order_of_key(400)<<endl; // 5
rope example
typedef rope<char> crope; //crope = rope<char>
rope<int> rp, a, b, c;
rp[x];
rp.at(x);
rp.length();
rp.size();
rp.push_back(x);
rp.insert(pos, x); //insert x at position pos
rp.erase(pos, x); //erase x elements from pos
rp.replace(pos, x); //from position pos replace with x
rp.substr(pos, x); //rp[pos:pos+x]
rp.copy(pos, x, s); //from position pos to pos+x replace with s
a = b + c; //concat
rope<int> *his[100000];
his[i] = new rope<int> (*his[i - 1]);
Advanced Topics
- handle duplication (multi-set)
- Copy-on-Write (可持久化)
- history of tree (just like git)
- concept : only copy what need to be copied
- \(O(\log(n))\) new nodes per patch
- example : ASK(version, kth, l, r) + Update + Online
Samples
POJ 3580 SuperMemo
- Operations:
- ADD x y D
- REVERSE x y
- REVOLVE x y T
- INSERT x P
- DELETE x
- MIN x y
- Implicit Treap -> AC
- Good practice problem for interval operations
- Think : how to SUM x y
Note:
- SUM x, y => care ADD lazy mark (interval val += interval size*addv)
- sample solution?
UVa 12538 Version Controlled IDE
- Operatons:
- Start with empty string
- insert interval to position x
- delete interval
- Rope + Copy-on-Write = AC!
- Challenge:
- treap
- what if add operation like reverse(rope and treap)
Conclusion
- Treap is a powerful data structure in competitive programming
- However, many problems that can be solved by Treap have alternatives
- Get familiar with this powerful tool and strengthen your mind
Note:
Reference
Thanks All