关于重量平衡树的相关概念可以参考姊妹文章:重量平衡树之替罪羊树
Treap是依靠旋转来维护平衡的重量平衡树中最为好写的一中,因为它的旋转不是LL就是RR
对于每一个新的节点,它给这个节点分配了一个随机数,用作优先级,然后以这个优先级来维护一个堆结构
由于堆本身就是完全二叉树结构,这样维护之后的树就无限接近于完全二叉树,所以还是很神奇的
这棵树满足BST的一切性质,除了不能处理序列问题之外已经无敌了
应该说,抛去动态树问题之外,这是实战最好用的树了
我们还是先看定义:
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是统计答案用的临时变量
我们这里还是先介绍插入操作,平衡树问题如果不是处理序列的,建议就一个一个插
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值等进行维护
每次插入要判断一下是否满足堆结构,进行相应的旋转调整
下面给出旋转调整的函数,基本上可以作为左旋和右旋的模板了
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 }