BST 是 Treap 的基础。
只写一点基本操作方便自己理解。
性质:左儿子 < 自己 < 右儿子
上图

插入
根据性质,比当前结点小就插入左子树,大就插入右子树,相等直接令当前结点的 cnt++ 即可。
void insert(int o, int k) {//在当前结点 o 插入 k 值 tr[o].sz++; if (tr[o].val == k) { tr[o].cnt++; return; } if (v < tr[o].val) { if (tr[o].ls != 0) insert(tr[o].ls, k); else { tot++; tr[tot].val = k, tr[tot].sz = tr[tot].cnt = 1; tr[o].ls = tot; } } else { if (tr[o].rs != 0) insert(tr[o].rs, k); else { tot++; tr[tot].val = k, tr[tot].sz = tr[tot].cnt = 1; tr[o].rs = tot; } }
删除
直接找到该数字所在的结点,令 cnt-- 就好了。
代码就不写了
因为上面那位大佬没写
前驱
一个数的前驱是指小于这个数的最大的数。
如果当前结点的值大于这个数,直接递归进左子树中找,小于的话就递归进右子树中找。
int pre(int o, int k, int ans) { if (tr[o].val >= k) { if (!tr[o].ls) return ans; else return pre(tr[o].ls, k, ans); } else { if (!tr[o].rs) { if (tr[o].val < k) return tr[o].val;//必须小于这个数 else return ans; } else if (tr[o].cnt) return pre(tr[o].rs, k, tr[o].val);//注意此时当前结点的值一定小于 ans ,要更新 ans else return pre(tr[o].rs, k, ans); } }
后继
和前驱的方法是一样的。
int suf(int o, int k, int ans) { if (tr[o].val <= k) { if (!tr[o].rs) return ans; else return suf(tr[o].rs, k, ans); } else { if (!tr[o].ls) { if (tr[o].val > k) return tr[o].val; else return ans; } else if (tr[o].cnt) return suf(tr[o].ls, k, tr[o].val); else return suf(tr[o].ls, k, ans); } }
排名
当前结点的排名为它的左子树大小加上自己的 cnt ,如果小于要找的排名,就递归进右子树,并更新排名,否则先查找是否是当前结点,不是再去左子树。
int GetRank(int o, int rk) { if (!o) return INF; if (tr[tr[o].ls].sz >= rk) return GetRank(tr[o].ls, rk); else if (tr[tr[o].ls].sz + tr[o].cnt >= rk) return tr[o].val; return GetRank(tr[o].rs, rk - tr[tr[o].ls].sz - tr[o].cnt); }
找值
如果当前结点的值小于查询的值,就在右子树找,同时排名要加上当前结点左子树的大小和当前结点的 cnt 值,否则直接递归进左子树找。
int GetVal(int o, int k) { if (!o) return 0; if (tr[o].val == k) return tr[tr[o].ls].sz + 1; else if (tr[o].val > k) return GetVal(tr[o].ls, k); return GetVal(tr[o].rs, k) + tr[tr[o].ls].sz + tr[o].cnt; }
来源:https://www.cnblogs.com/hlw1/p/12254474.html