几种常用平衡树的概述(持续更新]

【咕咕咕】待更新

1. Treap

  Treap是一种基于旋转来维护平衡的平衡树,它通过给每个节点赋一个随机值,并按照该值维护大(或)根堆,以此实现平衡;也因此,它叫Treap ( Binaty Search Tree + heap )

  核心操作 : 左旋和右旋

         左旋 : 对节点x进行左旋操作,即把x的右子节点旋到左边,具体操作就是把右子树的左子节点连到x,x的右子节点连在x和x的父亲之间;

         右旋 : 旋左;

  代码如下 :

  1 //Author : 15owzLy1
  2 //luogu3369.cpp
  3 //2018 12 05      22:37:51
  4 #include <iostream>
  5 #include <cstdio>
  6 #include <cstring>
  7 #include <algorithm>
  8 #include <cstdlib>
  9 #define INF 2100000000
 10 typedef long long ll;
 11 typedef double db;
 12 template<typename T>inline void read(T &_) {
 13     _=0;int __=0;char ___=getchar();
 14     while(___<'0'||___>'9')__|=(___=='-'),___=getchar();
 15     while(___>='0'&&___<='9')_=(_<<1)+(_<<3)+(___^48),___=getchar();
 16     _=__?-_:_;
 17 }
 18 
 19 const int N = 100005;
 20 int q, opt, y, res;
 21 
 22 class Treap {
 23 #define t a[p]
 24 #define lson a[a[p].l]
 25 #define rson a[a[p].r]
 26 private :
 27     int tot; 
 28     struct node {
 29         int l, r, val, num, w, size;
 30     }a[N];
 31     inline void push_up(int p) {
 32         t.size=lson.size+rson.size+t.val;
 33     }
 34     inline void zig(int &p) {
 35         int ts=lson.r, tmp=t.l;
 36         lson.size=t.size;
 37         lson.r=p, t.l=ts;
 38         push_up(p);
 39         p=tmp;
 40     }
 41     inline void zag(int &p) {
 42         int ts=rson.l, tmp=t.r;
 43         rson.size=t.size;
 44         rson.l=p, t.r=ts;
 45         push_up(p);
 46         p=tmp;
 47     }
 48     inline void new_node(int &p, int x) {
 49         t=(node){0, 0, 1, x, rand(), 1};
 50     }
 51 public :
 52     int rt;
 53     void debug(int p) {
 54         if(t.l) debug(t.l);
 55         printf("num : %d  p : %d\n", t.num, p);
 56         if(t.r) debug(t.r);
 57     }
 58     void insert(int &p, int x) {
 59         if(!p) { p=++tot; new_node(p, x); return ; }
 60         ++t.size;
 61         if(t.num==x) ++t.val;
 62         else if(x<t.num) {
 63             insert(t.l, x);
 64             if(t.w<lson.w) zig(p);
 65         }
 66         else {
 67             insert(t.r, x);
 68             if(t.w<rson.w) zag(p);
 69         }
 70     }
 71     void del(int &p, int x) {
 72         if(t.num==x) {
 73             if(t.val>1) --t.val, --t.size;
 74             else if(t.l==0||t.r==0) p=t.l?t.l:t.r;
 75             else if(lson.w>rson.w) zig(p), del(p, x);
 76             else                   zag(p), del(p, x);
 77         }
 78         else if(x<t.num) { --t.size; del(t.l, x); }
 79         else             { --t.size; del(t.r, x); }
 80     }
 81     int query_rank(int p, int x) {
 82         if(x==t.num)     return lson.size+1;
 83         else if(x<t.num) return query_rank(t.l, x);
 84         else             return query_rank(t.r, x)+lson.size+t.val;
 85     }
 86     int query_num(int p, int x) {
 87         if(!p) return 0;
 88         if(lson.size<x&&lson.size+t.val>=x) return t.num;
 89         if(lson.size>=x) return query_num(t.l, x);
 90         return query_num(t.r, x-t.val-lson.size);
 91     }
 92     void query_pre(int p, int x) {
 93         if(!p) return ;
 94         if(x<=t.num) query_pre(t.l, x);
 95         else {
 96             res=t.num;
 97             query_pre(t.r, x);
 98         }
 99     }
100     void query_sub(int p, int x) {
101         if(!p) return ;
102         if(x>=t.num) query_sub(t.r, x);
103         else {
104             res=t.num;
105             query_sub(t.l, x);
106         }
107     }
108 }T;
109 
110 int main() {
111 #ifndef ONLINE_JUDGE
112     freopen("luogu3369.in","r",stdin);
113     freopen("luogu3369.out","w",stdout);
114 #endif
115     srand(20030215);
116     read(q);
117     while(q--) {
118         read(opt), read(y);
119         if(opt==1)        T.insert(T.rt, y);
120         else if(opt==2) T.del(T.rt, y);
121         else if(opt==3) printf("%d\n", T.query_rank(T.rt, y));
122         else if(opt==4) printf("%d\n", T.query_num(T.rt, y));
123         else if(opt==5) {
124             res=-INF;
125             T.query_pre(T.rt, y);
126             printf("%d\n", res);
127         }
128         else {
129             res=INF;
130             T.query_sub(T.rt, y);
131             printf("%d\n", res);
132         }
133     }
134     return 0;
135 }
View Code

2. Splay

  Splay是一种基于旋转来维护平衡的平衡树,它通过旋转操作破坏当前存在的链维护相对平衡;

  核心操作 : Splay ,rotate

         Splay : 把x旋到根。如果是一个“之”字形,就旋两次x;如果是一条直链,就旋fa[x],再旋x;

         rotate : 旋转操作;

  Splay支持区间操作:处理l,r区间,可以先把节点l-1旋到根,再把r+1旋到l-1的右子树,r+1的左子树就是l,r区间;

  代码如下:

 1 //Author : 15owzLy1
 2 //luogu3391.cpp
 3 //2018 12 11      10:38:52
 4 #include <cstdio>
 5 #include <cstring>
 6 #include <algorithm>
 7 #define INF 2100000000
 8 typedef long long ll;
 9 typedef double db;
10 template<typename T>inline void read(T &_) {
11     _=0;int __=0;char ___=getchar();
12     while(___<'0'||___>'9')__|=(___=='-'),___=getchar();
13     while(___>='0'&&___<='9')_=(_<<1)+(_<<3)+(___^48),___=getchar();
14     _=__?-_:_;
15 }
16 
17 const int N = (int)1e5+5;
18 int n, q, x, y;
19 
20 class Splay {
21 #define lson c[p][0]
22 #define rson c[p][1]
23 private :
24     int c[N][2], fa[N], size[N], num[N], lazy[N];
25     inline void push_up(int p) {
26         size[p]=size[lson]+size[rson]+1;
27     }
28     inline void push_down(int p) {
29         if(lazy[p]) {
30             std::swap(lson, rson);
31             lazy[lson]^=1, lazy[rson]^=1;
32             lazy[p]=0;
33         }
34     }
35     inline void rotate(int x, int &p) {
36         int y=fa[x], z=fa[y], l, r;
37         l=(c[y][1]==x); r=l^1;
38         if(y==p) p=x;
39         else     c[z][c[z][1]==y]=x;
40         fa[c[x][r]]=y, fa[x]=z, fa[y]=x;    
41         c[y][l]=c[x][r], c[x][r]=y;
42         push_up(x), push_up(y);
43     }
44 public :
45     int rt;
46     inline void splay(int x, int &p) {
47         while(x!=p) {
48             int y=fa[x], z=fa[y];
49             if(y!=p) {
50                 if(c[y][0]==x^c[z][0]==y) rotate(x, p);
51                 else rotate(y, p);
52             }
53             rotate(x, p);
54         }
55     }
56     int find(int p, int rank) {
57         push_down(p);
58         if(size[lson]+1==rank)   return p;
59         else if(size[lson]>=rank)return find(lson, rank);
60         else                  return find(rson, rank-size[lson]-1);
61     }
62     inline void reverse(int x, int y) {
63         int l=find(rt, x), r=find(rt, y+2);
64         splay(l, rt), splay(r, c[l][1]);
65         lazy[c[r][0]]^=1;
66     }
67     void build(int l, int r, int father) {
68         if(l>r) return ;
69         int mid=l+r>>1;
70         c[father][mid>=father]=mid;
71         fa[mid]=father; size[mid]=1;
72         if(l==r) return ;
73         build(l, mid-1, mid);
74         build(mid+1, r, mid);
75         push_up(mid);
76     }
77 }T;
78 
79 int main() {
80 #ifndef ONLINE_JUDGE
81     freopen("luogu3391.in","r",stdin);
82 #endif
83     read(n), read(q);
84     T.rt=(n+3)>>1; T.build(1, n+2, T.rt);
85     while(q--) {
86         read(x), read(y);
87         T.reverse(x, y);
88     }
89     for(int i=2;i<=n+1;i++)
90         printf("%d ", T.find(T.rt, i)-1);
91     return 0;
92 }
View Code

3. FHQ Treap ( Persistence Treap)

  非旋Treap;

  核心操作:split,merge

         split:把当前的Treap分成两棵树,一棵上所有的节点大小<=k,另一棵>k;(递归实现

       merge :把两棵Treap合并,此时节点的大小已经满足平衡树定义,所以需要和Treap一样维护堆;

       通过split和merge,基本所有操作都可以暴力搞出来;

  代码如下 :

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <cstdlib>
  5 
  6 template<typename T>inline void read(T &x) {
  7     x=0;int f=0;char c=getchar();
  8     while(c<'0'||c>'9')f|=(c=='-'), c=getchar();
  9     while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48), c=getchar();
 10     x=f?-x:x;
 11 }
 12 
 13 const int N = (int)1e5+5;
 14 int q, opt, n;
 15 
 16 class fhq_Treap {
 17 #define t a[p]
 18 #define lson a[a[p].l]
 19 #define rson a[a[p].r]
 20 private :
 21     struct node {
 22         int l, r, num, size, w;
 23     }a[N];
 24     inline void push_up(int p) {
 25         t.size=lson.size+rson.size+1;
 26     }
 27     void split(int p, int &x, int &y, int k) {
 28         if(!p) { x=y=0; return ; }
 29         if(t.num<=k) x=p, split(t.r, t.r, y, k);
 30         else         y=p, split(t.l, x, t.l, k);
 31         push_up(p);
 32     }
 33     int merge(int &p, int x, int y) {
 34         if(x==0||y==0) { p=x?x:y; return p; }
 35         if(a[x].w<a[y].w) { p=x; merge(t.r, t.r, y); }
 36         else              { p=y; merge(t.l, x, t.l); }
 37         push_up(p);
 38         return p;
 39     }
 40     inline int new_node(int k) {
 41         a[++tot]=(node){0, 0, k, 1, rand()};
 42         return tot;
 43     }
 44 public :
 45     int rt, tot;
 46     void debug(int p) {
 47         if(t.l) debug(t.l);
 48         printf("   %d %d %d %d\n", t.num, lson.num, rson.num, t.size);
 49         if(t.r) debug(t.r);
 50     }
 51     inline void insert(int k) {
 52         int x=0, y=0, z=new_node(k);
 53         split(rt, x, y, k);
 54         merge(rt, merge(x, x, z), y);
 55     }
 56     inline void remove(int k) {
 57         int x=0, y=0, z=0;
 58         split(rt, x, y, k);
 59         split(x, x, z, k-1);
 60         merge(rt, merge(x, x, merge(z, a[z].l, a[z].r)), y);
 61     }
 62     inline int find(int k) {
 63         int x=0, y=0, ret;
 64         split(rt, x, y, k-1);
 65         ret=a[x].size+1;
 66         merge(rt, x, y);
 67         return ret;
 68     }
 69     inline int kth(int p, int k) {
 70         while(lson.size+1!=k) {
 71             if(lson.size>=k) p=t.l;
 72             else             k-=lson.size+1, p=t.r;
 73         }
 74         return t.num;
 75     }
 76     inline int query_pre(int k) {
 77         int x=0, y=0, ret;
 78         split(rt, x, y, k-1);
 79         ret=kth(x, a[x].size);
 80         merge(rt, x, y);
 81         return ret;
 82     }
 83     inline int query_sub(int k) {
 84         int x=0, y=0, ret;
 85         split(rt, x, y, k);
 86         ret=kth(y, 1);
 87         merge(rt, x, y);
 88         return ret;
 89     }
 90 }T;
 91 
 92 int main() {
 93 #ifndef ONLINE_JUDGE
 94     freopen("fhq_treap.in", "r", stdin);
 95 #endif
 96     srand(20030215);
 97     read(q);
 98     while(q--) {
 99         read(opt), read(n);
100         switch(opt) {
101             case 1 : T.insert(n);break;
102             case 2 : T.remove(n);break;
103             case 3 : printf("%d\n", T.find(n));break;
104             case 4 : printf("%d\n", T.kth(T.rt, n));break;
105             case 5 : printf("%d\n", T.query_pre(n));break;
106             case 6 : printf("%d\n", T.query_sub(n));break;
107         }
108     }
109     return 0;
110 }
View Code

4. 可持久化平衡树

  由于要维护历史版本,基于旋转的平衡树就不适用;常用的有两种 fhq treap 和 替罪羊树(复杂度假的),这里主要介绍 fhq treap;

  再fhq的split操作里,是唯一可能对历史版本造成影响的,所以只需要把这些节点复制,添加在当前的版本里,其他的直接用以前的版本即可;

  至于 merge 操作,把新建的节点合并即可;

  代码如下 :

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #define INF 2147483647
  5 
  6 template<typename T>inline void read(T &x) {
  7     x=0;int f=0;char c=getchar();
  8     while(c<'0'||c>'9')f|=(c=='-'), c=getchar();
  9     while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48), c=getchar();
 10     x=f?-x:x;
 11 }
 12 
 13 const int N = (int)5e5+5;
 14 int q, n, opt, tim;
 15 
 16 class Persistable_Treap {
 17 #define t a[p]
 18 #define lson a[a[p].l]
 19 #define rson a[a[p].r]
 20 private :
 21     struct node {
 22         int l, r, num, size, w;
 23     }a[N*50];
 24     int tot;
 25     
 26     inline void push_up(int p) { t.size=lson.size+rson.size+1; }
 27     inline int new_node(int k) {
 28         a[++tot]=(node){0, 0, k, 1, rand()};
 29         return tot;
 30     }
 31     inline int c0py(int p) {
 32         a[++tot]=t;
 33         return tot;
 34     }
 35     void split(int p, int &x, int &y, int k) {
 36         if(!p) { x=y=0; return ; }
 37         if(t.num<=k) p=x=c0py(p), split(t.r, t.r, y, k);
 38         else         p=y=c0py(p), split(t.l, x, t.l, k);
 39         push_up(p);
 40     }
 41     int merge(int x, int y) {
 42         if(!x||!y) return x?x:y;
 43         int p;
 44         if(a[x].w<a[y].w) p=x, t.r=merge(t.r, y);
 45         else              p=y, t.l=merge(x, t.l);
 46         push_up(p);
 47         return p;
 48     }
 49 public :
 50     int rt[N];
 51     void debug(int p) {
 52         if(t.l) debug(t.l);
 53         printf("     %d\n", t.num);
 54         if(t.r) debug(t.r);
 55     }
 56     inline void insert(int &p, int k) {
 57         int x, y;
 58         split(p, x, y, k);
 59         p=merge(merge(x, new_node(k)), y);
 60     }
 61     inline void remove(int &p, int k) {
 62         int x, y, z;
 63         split(p, x, y, k), split(x, x, z, k-1);
 64         p=merge(merge(x, merge(a[z].l, a[z].r)), y);
 65     }
 66     inline int rank(int &p, int k) {
 67         int x, y, ret;
 68         split(p, x, y, k-1);
 69         ret=a[x].size+1;
 70         p=merge(x, y);
 71         return ret;
 72     }
 73     inline int kth(int p, int k) {
 74         while(lson.size+1!=k)
 75             if(lson.size>=k)     p=t.l;
 76             else k-=lson.size+1, p=t.r;
 77         return t.num;
 78     }
 79     inline int pre(int &p, int k) {
 80         int x, y, ret;
 81         split(p, x, y, k-1);
 82         if(!x) return -INF;
 83         ret=kth(x, a[x].size);
 84         p=merge(x, y);
 85         return ret;
 86     }
 87     inline int sub(int &p, int k) {
 88         int x, y, ret;
 89         split(p, x, y, k);
 90         if(!y) return INF;
 91         ret=kth(y, 1);
 92         p=merge(x, y);
 93         return ret;
 94     }
 95 }T;
 96 
 97 int main() {
 98 #ifndef ONLINE_JUDGE
 99     freopen("luogu3835.in", "r", stdin);
100 #endif
101     srand(20021111);
102     read(q);
103     for(int i=1;i<=q;i++) {
104         read(tim), read(opt), read(n);
105         T.rt[i]=T.rt[tim];
106         if(opt==1)        T.insert(T.rt[i], n);
107         else if(opt==2) T.remove(T.rt[i], n);
108         else if(opt==3)    printf("%d\n", T.rank(T.rt[i], n));
109         else if(opt==4) printf("%d\n", T.kth(T.rt[i], n));
110         else if(opt==5) printf("%d\n", T.pre(T.rt[i], n));
111         else if(opt==6) printf("%d\n", T.sub(T.rt[i], n));
112     }
113     return 0;
114 }
View Code

 

posted @ 2018-12-12 11:44  15owzLy1  阅读(730)  评论(0编辑  收藏  举报