高rong效chang的可持久化treap
2016-05-18 15:27
337 查看
很多人觉得可持久化treap很慢,但是事实上只是他们可持久化treap的写法不对。他们一般是用split和merge实现所有功能,但是这样会有许多不必要的分裂。其实我们可以用一种特殊的方式来实现插入和删除。
插入:我们先随机出新建节点的Rank值,随二叉查找树的顺序找到第一个Rank比新建节点Rank小的节点,将以这个节点为根的子树按Key值分裂成两颗树并作为新建节点的左子树和右子树。
删除:我们用二叉查找树的方式找到删除节点,释放节点空间并将节点左子树和右子树合并代替原树。
由于随机构建二叉查找树从每个节点到叶节点期望距离是O(1)的,所以在插入删除中期望合并的树的深度是O(1)的。这样一来插入删除的log常数就只受查找速度影响(貌似比普通treap还快)
插入:我们先随机出新建节点的Rank值,随二叉查找树的顺序找到第一个Rank比新建节点Rank小的节点,将以这个节点为根的子树按Key值分裂成两颗树并作为新建节点的左子树和右子树。
删除:我们用二叉查找树的方式找到删除节点,释放节点空间并将节点左子树和右子树合并代替原树。
由于随机构建二叉查找树从每个节点到叶节点期望距离是O(1)的,所以在插入删除中期望合并的树的深度是O(1)的。这样一来插入删除的log常数就只受查找速度影响(貌似比普通treap还快)
#include<cstdio> #include<cstdlib> #include<algorithm> using namespace std ; struct Node { int Key ; int Rank ; int Size ; Node * L ; Node * R ; Node ( int , int , int ) ; void maintain () ; } ; Node * Nil = new Node ( 0 , INT_MIN , 0 ) ; Node :: Node ( const int Key = 0 , const int Rank = ( rand () ) , const int Size = 1 ) : Key ( Key ) , Rank ( Rank ) , Size ( Size ) , L ( Nil ) , R ( Nil ) {} void Node :: maintain () { Size = L -> Size + 1 + R -> Size ; } Node * Merge ( Node * const L , Node * const R ) { if ( L == Nil ) return R ; else if ( R == Nil ) return L ; else if ( L -> Rank > R -> Rank ) { L -> R = Merge ( L -> R , R ) ; L -> maintain () ; return L ; } else { R -> L = Merge ( L , R -> L ) ; R -> maintain () ; return R ; } } typedef pair < Node * , Node * > Npair ; void Split1 ( Node * const O , const int K , Node * & L , Node * & R ) { if ( O == Nil ) L = R = Nil ; else if ( O -> L -> Size <= K ) { Split1 ( O -> L , K , L , R ) ; O -> L = R ; R = O ; O -> maintain () ; } else { Split1 ( O -> R , K - ( O -> L -> Size + 1 ) , L , R ) ; O -> R = L ; L = O ; O -> maintain () ; } } void Split2 ( Node * const O , const int Key , Node * & L , Node * & R ) { if ( O == Nil ) L = R = Nil ; else if ( Key <= O -> Key ) { Split2 ( O -> L , Key , L , R ) ; O -> L = R ; R = O ; O -> maintain () ; } else { Split2 ( O -> R , Key , L , R ) ; O -> R = L ; L = O ; O -> maintain () ; } } int GetRank ( const Node * O , const int Key ) { int ans = 0 ; while ( O != Nil ) { if ( O -> Key <= Key ) { O = O -> L ; } else { ans += O -> L -> Size + 1 ; O = O -> R ; } } return ans ; } void Erase ( Node * & O , const int Key ) { if ( O == Nil ) return ; else if ( O -> Key == Key ) O = Merge ( O -> L , O -> R ) ; else if ( Key < O -> Key ) { Erase ( O -> L , Key ) ; O -> maintain () ; } else { Erase ( O -> R , Key ) ; O -> maintain () ; } } void Insert ( Node * & O , const int Key , const int Rank = rand () ) { if ( O -> Rank < Rank ) { Node * const np = new Node ( Key ) ; Split2 ( O , Key , np -> L , np -> R ) ; ( O = np ) -> maintain () ; } else if ( Key < O -> Key ) { Insert ( O -> L , Key , Rank ) ; O -> maintain () ; } else { Insert ( O -> R , Key , Rank ) ; O -> maintain () ; } }
相关文章推荐
- Session实现表单重复提交验证
- [从头学数学] 第211节 带着计算机去高考(三)
- 利用HTML5实现移动端的涂鸦
- 简述NotificationCenter、KVC、KVO、Delegate?并说明它们之间的区别?
- JS与iOS交互之OC获取JS内容跳转到指定控制器实现技巧
- IE8中往数组放值的问题
- jQuery获取文本节点之 text()/val()/html() 方法区别
- 盖得化工4——多线程+余数
- Resources和 AssetBundle 的区别
- android 中BroadcastReceiver 深入理解
- jQuery实现图片向左向右切换效果的简单实例
- Java编程思想第四版第七章学习(1)——基类初始化
- Sort Colors
- Jquery “回到顶部”
- 解决MindManager缺少mfc100u.dll无法启动的难题-转载
- HDU-3189-Just Do It【分解质因数】
- 转载:VBA中使用vlookup函数
- 浅析C#中StringBuilder类的高效及与String的对比
- 重读java编程思想之复用类之final
- 无密码登陆