已經兩個月沒有寫博客了,今天忽然想寫了(實際上是在補前的)我一直沒有看懂treap;如今有點感受了,就準備寫一篇論文,可能有點low;node
首先,要知道二叉查找樹是啥,這就要請度娘:二叉查找樹 百度百科
c++
明白二叉查找樹就行;函數
接着開始騷操做: 平衡樹有7大騷操做: 1.treap旋轉(zig/zag)操做 2.treap插入操做 3.treap刪除操做 4.求一個元素在treap的前驅 5.求一個元素在treap的後繼spa
6.在treap中查找排名第K的元素 7.在treap中求元素的排名 code
就這樣就從第一個開始講起:blog
首先我要先然你們看懂個人結構體:排序
1 struct node{ 2 int l; //左子節點 3 int r; //右子節點 4 int pri; //每一個節點的權值 5 int key; //優先級 6 int sze; //以x爲根的左子節點的個數 7 int same; //記錄重複節點的個數 8 }e[N*2];
1.treap(zig/zag)遞歸
首先一棵treap樹要保存一個最小堆的性質而這個最小堆性質就有隨機生成的key來維護:get
圖中的紅色部分就是隨機生成的key他要符合最小堆的性質,可是插入一個數他可能會不符合最小堆的性質時就要用到左轉右轉來維護這個最小堆;博客
如:左圖他就破壞了堆的性質就要把它左右旋,圖中將12進行右旋獲得一個符合條件的樹;
zig:
1 void zig(int &k) //這裏必需要加上一個&符號處理父子關係 2 { 3 int y=e[k].l; //選取當前結點的左子節點 4 e[k].l=e[y].r; 5 e[y].r=k; //交換y,k的父子位置,維護BST性質 6 e[y].sze=e[k].sze; //維護子樹的size 7 upt(k); //更新節點k的size 8 k=y; 9 } 10 //BST就是二叉搜索樹
zag:
和上面同樣操做
1 void zag(int &k) 2 { 3 int y=e[k].r; 4 e[k].r=e[y].l; 5 e[y].l=k; 6 e[y].sze=e[k].sze; 7 upt(k); 8 k=y; 9 } 10 和上方的zig的操做同樣,就很少說了(就是左改爲了右)
2.treap插入操做
給節點隨機分配一個優先級,先和二叉排序樹的插入同樣,先把要插入的點插入到一個葉子上,而後跟維護堆同樣,若是當前節點的優先級比根大就旋轉,若是當前節點是跟的左兒子就右旋若是當前節點是跟個右兒子就左旋。
代碼實現:
1 void Insert(int &k,const int &pre) 2 { 3 if(!k) 4 { 5 k=++pool;e[k].pri=pre;e[k].key=rand(); //rand()是隨機函數就是講樹節點的key隨機生成 6 e[k].same=e[k].sze=1;e[k].l=e[k].r=0; //新建節點 7 return ; 8 } 9 else ++e[k].sze; 10 if(e[k].pri==pre) ++e[k].same; //重複節點的處理 11 else if(pre<e[k].pri) 12 { 13 Insert(e[k].l,pre); 14 if(e[e[k].l].key<e[k].key) //維護堆的性質 15 zig(k); 16 } 17 else 18 { 19 Insert(e[k].r,pre); 20 if(e[e[k].r].key<e[k].key) //同上 21 zag(k); 22 } 23 return ; 24 }
3.treap刪除操做
有了旋轉的操做以後,Treap的刪除比二叉排序樹還要簡單。由於Treap知足堆性質,因此咱們只須要把要刪除的節點旋轉到葉節點上,而後直接刪除就能夠了。具體的方法就是每次找到優先級最大的兒子,向與其相反的方向旋轉,直到那個節點被旋轉到葉節點,而後直接刪除。
代碼:
1 void Delete(int &k,const int &pre) 2 { 3 if(e[k].pri==pre) 4 { 5 if(e[k].same>1) 6 { 7 --e[k].same; 8 --e[k].sze; 9 } 10 else if(!e[k].l||!e[k].r) 11 k=e[k].l+e[k].r; 12 else if(e[e[k].l].key<e[e[k].r].key) 13 { 14 zig(k); 15 Delete(k,pre); 16 } 17 else 18 { 19 zag(k); 20 Delete(k,pre); 21 } 22 return ; 23 } 24 --e[k].sze; 25 if(pre<e[k].pri) 26 Delete(e[k].l,pre); 27 else 28 Delete(e[k].r,pre); 29 return ; 30 }
4.求一個元素在treap的前驅
1.從根節點開始訪問,初始化最優節點爲空節點;
2.若是當前節點的值不大於要求前驅的元素的值,更新最優節點爲當前節點,訪問當前節點的右子節點;
3.若是當前節點的值大於要求前驅的元素的值,訪問當前節點的左子節點;
4.若是當前節點是空節點,查找結束,最優節點就是要求的前驅。
代碼:
1 int qianqu(const int &key) 2 { 3 int x=rt,res=-INF; 4 while(x) 5 { 6 if(e[x].pri<key) 7 { 8 res=e[x].pri; 9 x=e[x].r;//要求的前驅爲節點x或在節點x的右節點x的右子樹內 10 } 11 else 12 x=e[x].l; 13 } 14 return res; 15 }
5.求一個元素在treap的後繼
和前驅的基本同樣:
1 int houji(const int &key) 2 { 3 int x=rt,res=INF; 4 while(x) 5 { 6 if(e[x].pri>key) 7 { 8 res=e[x].pri; 9 x=e[x].l; 10 } 11 else 12 x=e[x].r; 13 } 14 return res; 15 }
6.在treap中查找排名第K的元素
若是咱們想查找第k小的元素或者詢問某個元素在Treap中從小到大的排名時,咱們就必須知道每一個子樹中節點的個數。咱們稱以一個子樹的全部節點的權值之和,爲子樹的大小。因爲插入、刪除、旋轉等操做,會使每一個子樹的大小改變,因此咱們必須對子樹的大小進行動態的維護。
對於旋轉,咱們要在旋轉後對子節點和根節點分別從新計算其子樹的大小。
對於插入,新創建的節點的子樹大小爲1。在尋找插入的位置時,每通過一個節點,都要先使以它爲根的子樹的大小增長1,再遞歸進入子樹查找。
對於刪除,在尋找待刪除節點,遞歸返回時要把全部的通過的節點的子樹的大小減小1。要注意的是,刪除以前必定要保證待刪除節點存在於Treap中。
1 int di(int &k) 2 { 3 int x=rt; 4 while(x) 5 { 6 if(e[e[x].l].sze<k&&e[e[x].l].sze+e[x].same>=k) 7 return e[x].pri; 8 if(e[e[x].l].sze>=k) x=e[x].l; 9 else 10 { 11 k-=e[e[x].l].sze+e[x].same; 12 x=e[x].r; 13 } 14 } 15 return 0; 16 }
7.在treap中求元素的排名
1 int piming(const int &key) 2 { 3 int x=rt,res=0; 4 while(x) 5 { 6 if(key==e[x].pri) 7 return res+e[e[x].l].sze+1; 8 if(key<e[x].pri) x=e[x].l; 9 else 10 { 11 res+=e[e[x].l].sze+e[x].same; 12 x=e[x].r; 13 } 14 } 15 return res; 16 }
這個應該是容易操做的;
最後貼一整個代碼:
1 #include<bits/stdc++.h> 2 #define INF 0x7fffff 3 #define N 100010 4 using namespace std; 5 struct node{ 6 int l; 7 int r; 8 int pri; 9 int key; 10 int sze; 11 int same; 12 }e[N*2]; 13 int rt,pool,n; 14 void upt(const int &k) 15 { 16 e[k].sze=e[e[k].l].sze+e[e[k].r].sze+e[k].same; 17 } 18 void zig(int &k) 19 { 20 int y=e[k].l; 21 e[k].l=e[y].r; 22 e[y].r=k; 23 e[y].sze=e[k].sze; 24 upt(k); 25 k=y; 26 } 27 void zag(int &k) 28 { 29 int y=e[k].r; 30 e[k].r=e[y].l; 31 e[y].l=k; 32 e[y].sze=e[k].sze; 33 upt(k); 34 k=y; 35 } 36 void Insert(int &k,const int &pre) 37 { 38 if(!k) 39 { 40 k=++pool;e[k].pri=pre;e[k].key=rand(); 41 e[k].same=e[k].sze=1;e[k].l=e[k].r=0; 42 return ; 43 } 44 else ++e[k].sze; 45 if(e[k].pri==pre) ++e[k].same; 46 else if(pre<e[k].pri) 47 { 48 Insert(e[k].l,pre); 49 if(e[e[k].l].key<e[k].key) 50 zig(k); 51 } 52 else 53 { 54 Insert(e[k].r,pre); 55 if(e[e[k].r].key<e[k].key) 56 zag(k); 57 } 58 return ; 59 } 60 void Delete(int &k,const int &pre) 61 { 62 if(e[k].pri==pre) 63 { 64 if(e[k].same>1) 65 { 66 --e[k].same; 67 --e[k].sze; 68 } 69 else if(!e[k].l||!e[k].r) 70 k=e[k].l+e[k].r; 71 else if(e[e[k].l].key<e[e[k].r].key) 72 { 73 zig(k); 74 Delete(k,pre); 75 } 76 else 77 { 78 zag(k); 79 Delete(k,pre); 80 } 81 return ; 82 } 83 --e[k].sze; 84 if(pre<e[k].pri) 85 Delete(e[k].l,pre); 86 else 87 Delete(e[k].r,pre); 88 return ; 89 } 90 int qianqu(const int &key) 91 { 92 int x=rt,res=-INF; 93 while(x) 94 { 95 if(e[x].pri<key) 96 { 97 res=e[x].pri; 98 x=e[x].r; 99 } 100 else 101 x=e[x].l; 102 } 103 return res; 104 } 105 int houji(const int &key) 106 { 107 int x=rt,res=INF; 108 while(x) 109 { 110 if(e[x].pri>key) 111 { 112 res=e[x].pri; 113 x=e[x].l; 114 } 115 else 116 x=e[x].r; 117 } 118 return res; 119 } 120 int di(int &k) 121 { 122 int x=rt; 123 while(x) 124 { 125 if(e[e[x].l].sze<k&&e[e[x].l].sze+e[x].same>=k) 126 return e[x].pri; 127 if(e[e[x].l].sze>=k) x=e[x].l; 128 else 129 { 130 k-=e[e[x].l].sze+e[x].same; 131 x=e[x].r; 132 } 133 } 134 return 0; 135 } 136 int piming(const int &key) 137 { 138 int x=rt,res=0; 139 while(x) 140 { 141 if(key==e[x].pri) 142 return res+e[e[x].l].sze+1; 143 if(key<e[x].pri) x=e[x].l; 144 else 145 { 146 res+=e[e[x].l].sze+e[x].same; 147 x=e[x].r; 148 } 149 } 150 return res; 151 } 152 int main() 153 { 154 scanf("%d",&n); 155 for(int i=1;i<=n;i++) 156 { 157 int opt,x; 158 scanf("%d%d",&opt,&x); 159 if(opt==1) 160 Insert(rt,x); 161 if(opt==2) 162 Delete(rt,x); 163 if(opt==3) 164 printf("%d\n",piming(x)); 165 if(opt==4) 166 printf("%d\n",di(x)); 167 if(opt==5) 168 printf("%d\n",qianqu(x)); 169 if(opt==6) 170 printf("%d\n",houji(x)); 171 } 172 return 0; 173 }