Treap模板
前言
打ACM這么久了,竟然還不會寫平衡樹,趁寒假有時間趕緊學一波,聽說有個叫Treap的實現起來比較簡單。聲明
struct node{int key,prio,sz;int ch[2]; }treap[maxn]; //key是存儲在節點內部有意義的值 //prio是隨機優先權,用于平衡樹堆 //sz表示該節點子樹的大小 int tot,root; //tot表示節點池使用情況 //root表示一顆Treap的根旋轉操作
void rotate(int &rt,bool d){//d為旋轉方向:0向左,1向右int x = rt;rt = treap[rt].ch[!d];treap[x].ch[!d] = treap[rt].ch[d];treap[rt].ch[d] = x;treap[x].sz = treap[treap[x].ch[0]].sz + 1 + treap[treap[x].ch[1]].sz;treap[rt].sz = treap[treap[rt].ch[0]].sz + 1 + treap[treap[rt].ch[1]].sz; }隨機數算法
int randint(){static int seed = 703;return seed = int(seed*48271LL%2147483647); } //這樣可以不重復的取遍int類型的隨機數插入
void ins(int &rt,int key){if(!rt) { //插入到目標處則新建一個節點rt = ++tot;treap[rt].key = key;treap[rt].prio = randint();treap[rt].sz = 1;}else{bool d = key > treap[rt].key; //目標方向ins(treap[rt].ch[d],key);treap[rt].sz ++;if(treap[rt].prio < treap[treap[rt].ch[d]].prio)rotate(rt,!d); //根據優先權進行旋轉 } }刪除
//刪除值為key的1個節點,若成功返回true bool erase(int &rt,int key){if(!rt) return false; if(key != treap[rt].key){if(erase(treap[rt].ch[key > treap[rt].key],key)){treap[rt].sz--;return true;}return false;}else if(treap[rt].ch[0] == 0) rt = treap[rt].ch[1];else if(treap[rt].ch[1] == 0) rt = treap[rt].ch[0];else{int &lft = treap[rt].ch[0],&rgt = treap[rt].ch[1];bool d = treap[lft].prio > treap[rgt].prio;rotate(rt,d);//遇見左右兒子都非空情況就將目標節點下傳,然后再刪除erase(treap[rt].ch[d],key);treap[rt].sz--;}return true; }選kth小
//注意!該函數返回值為節點的編號!!! //想要獲得kth小節點的key值,采用引用傳值方法!!! int select(int rt,int kth,int &key){if(kth > treap[rt].sz || kth < 1) return 0;//如果找傳入數據kth非法則返回0for(int nums;rt;){nums = treap[treap[rt].ch[0]].sz+1;if(nums == kth){key = treap[rt].key;return rt;}else if(nums < kth){kth -= nums;rt = treap[rt].ch[1];}elsert = treap[rt].ch[0];}return rt; }查元素x的rank
//注意!該函數的返回值也是節點編號,引用傳值的方式返回rank //該函數用于找到第一個節點值.key >= key的節點,并返回 //類似于lower_bound int getrank(int rt,int key,int &rank){int pre = 0,nums = 0,d;rank = 0;while(1){if(treap[rt].key >= key) pre = rt,rank = nums+treap[treap[rt].ch[0]].sz+1;d = key > treap[rt].key;if(!treap[rt].ch[d]) break;if(d) nums += treap[treap[rt].ch[0]].sz+1;rt = treap[rt].ch[d];}if(!pre) pre = rt,rank = nums+1+treap[treap[rt].ch[0]].sz;return pre; }小結
還是要多熟練,自己多動手寫一寫,用起來才會更加得心應手一些。 還有數的前驅和后繼都可以用select和getrank組合,請讀者手動實現。起碼會寫一種平衡樹了,不是嗎?
總結
- 上一篇: 大年初三有哪些习俗 正月初三有什么传统习
- 下一篇: codeforces D.MADMAX