很多人覺得可持久化treap很慢,但是事實上只是他們可持久化treap的寫法不對。他們一般是用split和merge實現所有功能,但是這樣會有許多不必要的分裂。其實我們可以用一種特殊的方式來實現插入和刪除。
插入:我們先隨機出新建節點的Rank值,隨二叉查找樹的順序找到第一個Rank比新建節點Rank小的節點,將以這個節點為根的子樹按Key值分裂成兩顆樹並作為新建節點的左子樹和右子樹。
刪除:我們用二叉查找樹的方式找到刪除節點,釋放節點空間並將節點左子樹和右子樹合並代替原樹。
由於隨機構建二叉查找樹從每個節點到葉節點期望距離是O(1)的,所以在插入刪除中期望合並的樹的深度是O(1)的。這樣一來插入刪除的log常數就只受查找速度影響(貌似比普通treap還快)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 using namespace std ; 5 6 struct Node { 7 int Key ; 8 int Rank ; 9 int Size ; 10 Node * L ; 11 Node * R ; 12 Node ( int , int , int ) ; 13 void maintain () ; 14 } ; 15 16 Node * Nil = new Node ( 0 , INT_MIN , 0 ) ; 17 18 Node :: Node ( const int Key = 0 , const int Rank = ( rand () ) , const int Size = 1 ) : 19 Key ( Key ) , Rank ( Rank ) , 20 Size ( Size ) , L ( Nil ) , R ( Nil ) {} 21 22 void Node :: maintain () { 23 Size = L -> Size + 1 + R -> Size ; 24 } 25 26 Node * Merge ( Node * const L , Node * const R ) { 27 if ( L == Nil ) return R ; 28 else if ( R == Nil ) return L ; 29 else if ( L -> Rank > R -> Rank ) { 30 L -> R = Merge ( L -> R , R ) ; 31 L -> maintain () ; 32 return L ; 33 } else { 34 R -> L = Merge ( L , R -> L ) ; 35 R -> maintain () ; 36 return R ; 37 } 38 } 39 40 typedef pair < Node * , Node * > Npair ; 41 42 void Split1 ( Node * const O , const int K , 43 Node * & L , Node * & R ) { 44 if ( O == Nil ) L = R = Nil ; 45 else if ( O -> L -> Size <= K ) { 46 Split1 ( O -> L , K , L , R ) ; 47 O -> L = R ; 48 R = O ; 49 O -> maintain () ; 50 } else { 51 Split1 ( O -> R , K - ( O -> L -> Size + 1 ) , L , R ) ; 52 O -> R = L ; 53 L = O ; 54 O -> maintain () ; 55 } 56 } 57 58 void Split2 ( Node * const O , const int Key , 59 Node * & L , Node * & R ) { 60 if ( O == Nil ) L = R = Nil ; 61 else if ( Key <= O -> Key ) { 62 Split2 ( O -> L , Key , L , R ) ; 63 O -> L = R ; 64 R = O ; 65 O -> maintain () ; 66 } else { 67 Split2 ( O -> R , Key , L , R ) ; 68 O -> R = L ; 69 L = O ; 70 O -> maintain () ; 71 } 72 } 73 74 int GetRank ( const Node * O , const int Key ) { 75 int ans = 0 ; 76 while ( O != Nil ) { 77 if ( O -> Key <= Key ) { 78 O = O -> L ; 79 } else { 80 ans += O -> L -> Size + 1 ; 81 O = O -> R ; 82 } 83 } 84 return ans ; 85 } 86 87 void Erase ( Node * & O , const int Key ) { 88 if ( O == Nil ) return ; 89 else if ( O -> Key == Key ) O = Merge ( O -> L , O -> R ) ; 90 else if ( Key < O -> Key ) { 91 Erase ( O -> L , Key ) ; 92 O -> maintain () ; 93 } else { 94 Erase ( O -> R , Key ) ; 95 O -> maintain () ; 96 } 97 } 98 99 void Insert ( Node * & O , const int Key , const int Rank = rand () ) { 100 if ( O -> Rank < Rank ) { 101 Node * const np = new Node ( Key ) ; 102 Split2 ( O , Key , np -> L , np -> R ) ; 103 ( O = np ) -> maintain () ; 104 } else if ( Key < O -> Key ) { 105 Insert ( O -> L , Key , Rank ) ; 106 O -> maintain () ; 107 } else { 108 Insert ( O -> R , Key , Rank ) ; 109 O -> maintain () ; 110 } 111 }