關於重量平衡樹的相關概念能夠參考姊妹文章:重量平衡樹之替罪羊樹ios
Treap是依靠旋轉來維護平衡的重量平衡樹中最爲好寫的一中,由於它的旋轉不是LL就是RR函數
對於每個新的節點,它給這個節點分配了一個隨機數,用做優先級,而後以這個優先級來維護一個堆結構spa
因爲堆自己就是徹底二叉樹結構,這樣維護以後的樹就無限接近於徹底二叉樹,因此仍是很神奇的code
這棵樹知足BST的一切性質,除了不能處理序列問題以外已經無敵了blog
應該說,拋去動態樹問題以外,這是實戰最好用的樹了ci
咱們仍是先看定義:it
struct Tree { int v,w; int size; int rnd; int ch[2]; }t[maxn]; int root; int size; int ans=0;
在這裏v是值,w是同值的節點個數,size是子樹的節點總數,rnd是優先級,外面:root是根節點,size是根節點中元素個數,ans是統計答案用的臨時變量io
咱們這裏仍是先介紹插入操做,平衡樹問題若是不是處理序列的,建議就一個一個插模板
void insert(int &k,int x) { if(k==0) { size++; k=size; t[k].size=t[k].w=1; t[k].v=x; t[k].rnd=rand(); return; } t[k].size++; if(t[k].v==x) t[k].w++; else if(x>t[k].v) { insert(t[k].ch[1],x); if(t[t[k].ch[1]].rnd<t[k].rnd) lturn(k); } else { insert(t[k].ch[0],x); if(t[t[k].ch[0]].rnd<t[k].rnd) rturn(k); } }
插入時根據是不是葉子節點,遍歷到的節點的w值等進行維護class
每次插入要判斷一下是否知足堆結構,進行相應的旋轉調整
下面給出旋轉調整的函數,基本上能夠做爲左旋和右旋的模板了
void rturn(int &k) { int tmp=t[k].ch[0]; t[k].ch[0]=t[tmp].ch[1]; t[tmp].ch[1]=k; t[tmp].size=t[k].size; update(k); k=tmp; } void lturn(int &k) { int tmp=t[k].ch[1]; t[k].ch[1]=t[tmp].ch[0]; t[tmp].ch[0]=k; t[tmp].size=t[k].size; update(k); k=tmp; }
而後咱們給出update函數,這裏要維護的東西不多,只有一個size,因此這個時候的update就是更新size用的
void update(int k) { t[k].size=t[t[k].ch[0]].size+t[t[k].ch[1]].size+t[k].w; }
而後是四種基本查詢工做,各類平衡樹基本一致,也能夠做爲模板記下來了
int query_rank(int k,int x) { if(k==0) return 0; if(t[k].v==x) return t[t[k].ch[0]].size+1; else if(x>t[k].v) return t[t[k].ch[0]].size+t[k].w+query_rank(t[k].ch[1],x); else return query_rank(t[k].ch[0],x); } int query_num(int k,int x) { if(k==0) return 0; if(x<=t[t[k].ch[0]].size) return query_num(t[k].ch[0],x); else if(x>t[t[k].ch[0]].size+t[k].w) return query_num(t[k].ch[1],x-t[t[k].ch[0]].size-t[k].w); else return t[k].v; } void query_pro(int k,int x) { if(k==0) return; if(t[k].v<x) ans=k,query_pro(t[k].ch[1],x); else query_pro(t[k].ch[0],x); } void query_sub(int k,int x) { if(k==0) return; if(t[k].v>x) ans=k,query_sub(t[k].ch[0],x); else query_sub(t[k].ch[1],x); }
最後咱們給出完整的模板,這棵樹必定要熟練掌握,只要是平衡樹問題,很大可能都是用它來完成的
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 using namespace std; 5 const int maxn=100005; 6 int n; 7 struct Tree 8 { 9 int v,w; 10 int size; 11 int rnd; 12 int ch[2]; 13 }t[maxn]; 14 int root; 15 int size; 16 int ans=0; 17 void update(int k) 18 { 19 t[k].size=t[t[k].ch[0]].size+t[t[k].ch[1]].size+t[k].w; 20 } 21 void rturn(int &k) 22 { 23 int tmp=t[k].ch[0]; 24 t[k].ch[0]=t[tmp].ch[1]; 25 t[tmp].ch[1]=k; 26 t[tmp].size=t[k].size; 27 update(k); 28 k=tmp; 29 } 30 void lturn(int &k) 31 { 32 int tmp=t[k].ch[1]; 33 t[k].ch[1]=t[tmp].ch[0]; 34 t[tmp].ch[0]=k; 35 t[tmp].size=t[k].size; 36 update(k); 37 k=tmp; 38 } 39 void insert(int &k,int x) 40 { 41 if(k==0) 42 { 43 size++; 44 k=size; 45 t[k].size=t[k].w=1; 46 t[k].v=x; 47 t[k].rnd=rand(); 48 return; 49 } 50 t[k].size++; 51 if(t[k].v==x) 52 t[k].w++; 53 else if(x>t[k].v) 54 { 55 insert(t[k].ch[1],x); 56 if(t[t[k].ch[1]].rnd<t[k].rnd) 57 lturn(k); 58 } 59 else 60 { 61 insert(t[k].ch[0],x); 62 if(t[t[k].ch[0]].rnd<t[k].rnd) 63 rturn(k); 64 } 65 } 66 void del(int &k,int x) 67 { 68 if(k==0) 69 return; 70 if(t[k].v==x) 71 { 72 if(t[k].w>1) 73 { 74 t[k].w--; 75 t[k].size--; 76 return; 77 } 78 if(t[k].ch[0]*t[k].ch[1]==0) 79 k=t[k].ch[0]+t[k].ch[1]; 80 else if(t[t[k].ch[0]].rnd<t[t[k].ch[1]].rnd) 81 rturn(k),del(k,x); 82 else 83 lturn(k),del(k,x); 84 } 85 else if(x>t[k].v) 86 t[k].size--,del(t[k].ch[1],x); 87 else 88 t[k].size--,del(t[k].ch[0],x); 89 } 90 int query_rank(int k,int x) 91 { 92 if(k==0) 93 return 0; 94 if(t[k].v==x) 95 return t[t[k].ch[0]].size+1; 96 else if(x>t[k].v) 97 return t[t[k].ch[0]].size+t[k].w+query_rank(t[k].ch[1],x); 98 else 99 return query_rank(t[k].ch[0],x); 100 } 101 int query_num(int k,int x) 102 { 103 if(k==0) 104 return 0; 105 if(x<=t[t[k].ch[0]].size) 106 return query_num(t[k].ch[0],x); 107 else if(x>t[t[k].ch[0]].size+t[k].w) 108 return query_num(t[k].ch[1],x-t[t[k].ch[0]].size-t[k].w); 109 else 110 return t[k].v; 111 } 112 void query_pro(int k,int x) 113 { 114 if(k==0) 115 return; 116 if(t[k].v<x) 117 ans=k,query_pro(t[k].ch[1],x); 118 else 119 query_pro(t[k].ch[0],x); 120 } 121 void query_sub(int k,int x) 122 { 123 if(k==0) 124 return; 125 if(t[k].v>x) 126 ans=k,query_sub(t[k].ch[0],x); 127 else 128 query_sub(t[k].ch[1],x); 129 } 130 int main() 131 { 132 cin>>n; 133 int tmp,x; 134 for(int i=1;i<=n;i++) 135 { 136 cin>>tmp>>x; 137 switch(tmp) 138 { 139 case 1:insert(root,x);break; 140 case 2:del(root,x);break; 141 case 3:cout<<query_rank(root,x)<<endl;break; 142 case 4:cout<<query_num(root,x)<<endl;break; 143 case 5:ans=0;query_pro(root,x);cout<<t[ans].v<<endl;break; 144 case 6:ans=0;query_sub(root,x);cout<<t[ans].v<<endl;break; 145 } 146 } 147 return 0; 148 }