平衡の树

平衡树

BST就是所谓的二叉平衡搜索树者也!

满足性质:中序遍历是单调递增的。

Splay Tree:

伸展树,先%%% Tarjan。

依靠旋转来维护,主要是靠splay里面的双旋。

反正我写个模板就打了220行,有剧毒......

主要函数有rotate,splay,getNbyV,insert,del等。

下面这个是一个简单的维护数的splay。

有两种插入方式,递归版亲测比非递归快一些,还能沿途更新,就是害怕爆栈,最好随时splay几下防止退化。

[update] 洛谷加了一组数据,递归版插入被hack了,非递归安然无恙。

支持重复数据,不支持pushdown,不支持空间回收。

  1 #include <cstdio>
  2 #define ot printf("root = %d Splay: ", spt.val[spt.root]);spt.out(spt.root);printf("\n")
  3 const int N = 1000010, INF = 0x3f3f3f3f;
  4 
  5 struct SplayTree {
  6     int s[N][2], fa[N], cnt[N], siz[N], val[N];
  7     int tot, root;
  8     inline void init() {
  9         tot = 2;
 10         root = 1;
 11         fa[2] = 1;
 12         s[1][1] = 2;
 13         val[1] = -INF;
 14         val[2] = INF;
 15         siz[1] = 2;
 16         siz[2] = 1;
 17         cnt[1] = cnt[2] = 1;
 18         return;
 19     }
 20     SplayTree() {
 21         init();
 22     }
 23     inline void clear() {
 24         for(int i = 1; i <= tot; i++) {
 25             fa[i] = cnt[i] = siz[i] = val[i] = 0;
 26             s[i][1] = s[i][0] = 0;
 27         }
 28         init();
 29         return;
 30     }
 31 
 32     inline void pushup(int x) {
 33         siz[x] = siz[s[x][1]] + siz[s[x][0]] + cnt[x];
 34         return;
 35     }
 36     inline void pushdown(int x) {
 37         return;
 38     }
 39 
 40     inline void rotate(int x) {
 41         int y = fa[x];
 42         int z = fa[y];
 43         bool f = (s[y][1] == x);
 44         //pushdown(y);
 45         //pushdown(x);
 46 
 47         if(z) {
 48             s[z][s[z][1] == y] = x;
 49         }
 50         fa[x] = z;
 51         fa[s[x][!f]] = y;
 52         s[y][f] = s[x][!f];
 53         fa[y] = x;
 54         s[x][!f] = y;
 55 
 56         pushup(y);
 57         pushup(x);
 58         if(!z) {
 59             root = x;
 60         }
 61         return;
 62     }
 63 
 64     inline void splay(int x, int g) {
 65         int y = fa[x];
 66         int z = fa[y];
 67         while(y != g) {
 68             if(z != g) { /// if(z)  if(z != root)
 69                 (s[z][1] == y) ^ (s[y][1] == x)
 70                 ? rotate(x) : rotate(y);
 71             }
 72             rotate(x);
 73             y = fa[x];
 74             z = fa[y];
 75         }
 76         return;
 77     }
 78 
 79     inline int getNbyV(int x) {
 80         int p = root, ans;
 81         while(1) {
 82             ans = p;
 83             if(val[p] == x) {
 84                 break;
 85             }
 86             if(val[p] > x && s[p][0]) {
 87                 p = s[p][0];
 88             }
 89             else if(val[p] < x && s[p][1]) {
 90                 p = s[p][1];
 91             }
 92             else {
 93                 break;
 94             }
 95         }
 96         splay(ans, 0);
 97         return ans;
 98     }
 99 
100     inline int getpre() {
101         int p = s[root][0];
102         while(s[p][1]) {
103             p = s[p][1];
104         }
105         return p;
106     }
107 
108     inline int getnex() {
109         int p = s[root][1];
110         while(s[p][0]) {
111             p = s[p][0];
112         }
113         return p;
114     }
115 
116     inline int newNode(int x, int f) {
117         ++tot;
118         cnt[tot] = siz[tot] = 1;
119         val[tot] = x;
120         fa[tot] = f;
121         return tot;
122     }
123 
124     inline void insert(int x) {
125         int p = root;
126         while(1) {
127             siz[p]++;
128             if(val[p] == x) {
129                 cnt[p]++;
130                 break;
131             }
132             if(x < val[p] && s[p][0]) {
133                 p = s[p][0];
134             }
135             else if(val[p] < x && s[p][1]) {
136                 p = s[p][1];
137             }
138             else {
139                 bool f = (val[p] < x);
140                 s[p][f] = newNode(x, p);
141                 p = s[p][f];
142                 break;
143             }
144         }
145         splay(p, 0);
146         return;
147     }
148     void insert(int x, int p) {
149         if(val[p] == x) {
150             cnt[p]++;
151         }
152         else if(x < val[p] && s[p][0]) {
153             insert(x, s[p][0]);
154         }
155         else if(x > val[p] && s[p][1]) {
156             insert(x, s[p][1]);
157         }
158         else {
159             bool f = (val[p] < x);
160             s[p][f] = newNode(x, p);
161         }
162         pushup(p);
163         return;
164     }
165 
166     inline void del(int x) {
167         int p = getNbyV(x);
168         if(cnt[p] > 1) {
169             cnt[p]--;
170             return;
171         }
172         int t = getpre();
173         splay(t, root);
174         p = s[root][1];
175 
176         fa[p] = t;
177         s[t][1] = p;
178         fa[t] = 0;
179         root = t;
180 
181         pushup(t);
182         return;
183     }
184 
185     inline int getRbyV(int x) {
186         int p = getNbyV(x);
187         return siz[s[p][0]] + 1;
188     }
189 
190     inline int getVbyR(int x) {
191         int p = root, t;
192         while(1) {
193             t = siz[s[p][0]];
194             if(t >= x) {
195                 p = s[p][0];
196             }
197             else if(t + cnt[p] >= x) {
198                 break;
199             }
200             else {
201                 x -= (t + cnt[p]);
202                 p = s[p][1];
203             }
204         }
205         return val[p];
206     }
207 
208     inline int getXpre(int x) {
209         int p = getNbyV(x);
210         if(val[p] >= x) {
211             p = getpre();
212             splay(p, 0);
213         }
214         return val[p];
215     }
216 
217     inline int getXnex(int x) {
218         int p = getNbyV(x);
219         if(val[p] <= x) {
220             p = getnex();
221             splay(p, 0);
222         }
223         return val[p];
224     }
225 
226     void out(int p) {
227         if(s[p][0]) {
228             out(s[p][0]);
229         }
230         printf("%d ", val[p]);
231         if(s[p][1]) {
232             out(s[p][1]);
233         }
234         return;
235     }
236 
237 }spt;
238 
239 int main() {
240     int n;
241     scanf("%d", &n);
242     for(int i = 1, f, x; i <= n; i++) {
243         scanf("%d%d", &f, &x);
244         if(f == 1) {
245             spt.insert(x, spt.root);
246             //ot;
247         }
248         else if(f == 2) {
249             spt.del(x);
250             //ot;
251         }
252         else if(f == 3) {
253             printf("%d\n", spt.getRbyV(x) - 1);
254         }
255         else if(f == 4) {
256             printf("%d\n", spt.getVbyR(x + 1));
257         }
258         else if(f == 5) {
259             printf("%d\n", spt.getXpre(x));
260         }
261         else if(f == 6) {
262             printf("%d\n", spt.getXnex(x));
263         }
264         else {
265             spt.clear();
266             //ot;
267         }
268     }
269     return 0;
270 }
洛谷P3369

[update20181025]发现我的代码中有个问题,在rotate的时候可能会把fa[0]赋值为y,但是并不影响什么.....

接下来是序列版splay,也就是重头戏:序列之王!

因为splay的中序遍历单调递增,我们可以据此维护下标。

但是我们并不维护真正的下标,只是维护它们的顺序!

这样就能够支持区间翻转,最值,插入,删除,修改了。

和数版splay稍有变化。

写的时候发现了一点小问题:

两个区间最值好像不能同时维护...

因为两个哨兵会让两个区间最值冲突而炸掉。

不知道有没有什么解决办法...

结果我就分开写了......

  1 #include <cstdio>
  2 #include <algorithm>
  3 const int N = 100010;
  4 
  5 struct SplayTree {
  6     int fa[N], s[N][2], siz[N], val[N], rev[N];
  7     int tot, root, ad[N];
  8 
  9     inline void pushup(int p) {
 10         siz[p] = siz[s[p][0]] + siz[s[p][1]] + 1;
 11         return;
 12     }
 13 
 14     inline void pushdown(int p) {
 15         if(!rev[p])  {
 16             return;
 17         }
 18         int ls = s[p][0], rs = s[p][1];
 19         if(ls) {
 20             rev[ls] ^= 1;
 21         }
 22         if(rs) {
 23             rev[rs] ^= 1;
 24         }
 25         std::swap(s[p][0], s[p][1]);
 26         rev[p] = 0;
 27         return;
 28     }
 29 
 30     int build(int l, int r, int f) {
 31         int mid = (l + r) >> 1;
 32         int p = ++tot;
 33         val[p] = ad[mid];
 34         fa[p] = f;
 35         if(l < mid) {
 36             s[p][0] = build(l, mid - 1, p);
 37         }
 38         if(mid < r) {
 39             s[p][1] = build(mid + 1, r, p);
 40         }
 41         pushup(p);
 42         return p;
 43     }
 44 
 45     inline void init() {
 46         root = 1;
 47         tot = 2; /// space
 48         fa[2] = 1;
 49         s[1][1] = 2;
 50         siz[2] = 1;
 51         siz[1] = 2;
 52         return;
 53     }
 54 
 55     SplayTree() {
 56         init();
 57     }
 58 
 59     inline void clear() {
 60         for(int i = 3; i <= tot; i++) {
 61             fa[i] = siz[i] = val[i]
 62             = s[i][0] = s[i][1] = rev[i] = 0;
 63         }
 64         tot = 2;
 65         root = 1;
 66         return;
 67     }
 68 
 69     inline void rotate(int x) {
 70         int y = fa[x];
 71         int z = fa[y];
 72         pushdown(y);
 73         pushdown(x);
 74         bool f = (s[y][1] == x);
 75 
 76         if(z) {
 77             s[z][s[z][1] == y] = x;
 78         }
 79         fa[x] = z;
 80         s[y][f] = s[x][!f];
 81         fa[s[x][!f]] = y;
 82         fa[y] = x;
 83         s[x][!f] = y;
 84 
 85         pushup(y);
 86         pushup(x);
 87         if(!z) {
 88             root = x;
 89         }
 90         return;
 91     }
 92 
 93     inline void splay(int x, int g) {
 94         int y = fa[x];
 95         int z = fa[y];
 96         while(y != g) {
 97             if(z != g)  {
 98                 (s[z][1] == y) ^ (s[y][1] == x)
 99                 ? rotate(x) : rotate(y);
100             }
101             rotate(x);
102             y = fa[x];
103             z = fa[y];
104         }
105         return;
106     }
107 
108     inline int getNbyR(int x) {
109         int p = root, t;
110         while(1) {
111             pushdown(p);
112             t = siz[s[p][0]];
113             if(t + 1 == x) {
114                 break;
115             }
116             else if(t + 1 > x) {
117                 p = s[p][0];
118             }
119             else  {
120                 x -= (t + 1);
121                 p = s[p][1];
122             }
123         }
124         return p;
125     }
126 
127     inline int get(int l, int r) {
128         r += 2;
129         int p = getNbyR(l);
130         splay(p, 0);
131         p = getNbyR(r);
132         splay(p, root);
133         return p;
134     }
135 
136     inline void reverse(int l, int r) {
137         int p = get(l, r);
138         p = s[p][0];
139         rev[p] ^= 1;
140         return;
141     }
142 
143     void out(int p) {
144         pushdown(p);
145         if(s[p][0]) {
146             out(s[p][0]);
147         }
148         if(val[p]) {
149             printf("%d ", val[p]);
150         }
151         if(s[p][1]) {
152             out(s[p][1]);
153         }
154         return;
155     }
156 
157     inline void insert(int l, int n) {
158         int p = get(l, l + 1);
159         s[p][1] = build(1, n, p);
160         pushup(p);
161         pushup(root);
162         return;
163     }
164 
165     inline void del(int l, int r) {
166         int p = get(l, r);
167         s[p][0] = 0;
168         pushup(p);
169         pushup(root);
170         return;
171     }
172 
173 }spt;
174 
175 int main() {
176     int m, n;
177     scanf("%d%d", &n, &m);
178     for(int i = 1; i <= n; i++) {
179         spt.ad[i] = i;
180     }
181     spt.s[2][0] = spt.build(1, n, 2);
182     for(int i = 1, x, y; i <= m; i++) {
183         scanf("%d%d", &x, &y);
184         spt.reverse(x, y);
185     }
186     spt.out(spt.root);
187     return 0;
188 }
洛谷P3391 翻转

(这个模板写的有点乱...)

  1 #include <cstdio>
  2 #include <algorithm>
  3 
  4 const int N = 1000010, INF = 0x7f7f7f7f;
  5 
  6 inline void Read(int &x) {
  7     x = 0;
  8     char c = getchar();
  9     while(c < '0' || c > '9') {
 10         c = getchar();
 11     }
 12     while(c >= '0' && c <= '9') {
 13         x = (x << 3) + (x << 1) + c - 48;
 14         c = getchar();
 15     }
 16     return;
 17 }
 18 
 19 struct SplayTree {
 20     int fa[N], s[N][2], siz[N];
 21     int val[N], small[N];
 22     int tot, root;
 23 
 24     SplayTree() {
 25         root = 1;
 26         tot = 2;
 27 
 28         val[1] = val[2] = INF;
 29         fa[2] = 1;
 30         s[1][1] = 2;
 31         siz[1] = 2;
 32         siz[2] = 1;
 33         small[1] = small[2] = INF;
 34     }
 35 
 36     inline void pushup(int p) {
 37         int ls = s[p][0];
 38         int rs = s[p][1];
 39         siz[p] = siz[ls] + siz[rs] + 1;
 40         small[p] = val[p];
 41         if(ls) {
 42             small[p] = std::min(small[p], small[ls]);
 43         }
 44         if(rs) {
 45             small[p] = std::min(small[p], small[rs]);
 46         }
 47         return;
 48     }
 49 
 50     int build(int l, int r, int f) {
 51         int mid = (l + r) >> 1;
 52         int p = ++tot;
 53 
 54         if(l < mid) {
 55             s[p][0] = build(l, mid - 1, p);
 56         }
 57         Read(val[p]);
 58         fa[p] = f;
 59         if(mid < r) {
 60             s[p][1] = build(mid + 1, r, p);
 61         }
 62 
 63         pushup(p);
 64         return p;
 65     }
 66 
 67     inline void rotate(int x) {
 68         int y = fa[x];
 69         int z = fa[y];
 70         bool f = (s[y][1] == x);
 71 
 72         if(z) {
 73             s[z][s[z][1] == y] = x;
 74         }
 75         fa[x] = z;
 76         s[y][f] = s[x][!f];
 77         fa[s[x][!f]] = y;
 78         fa[y] = x;
 79         s[x][!f] = y;
 80 
 81         pushup(y);
 82         pushup(x);
 83         if(!z) {
 84             root = x;
 85         }
 86         return;
 87     }
 88 
 89     inline void splay(int x, int g) {
 90         int y = fa[x];
 91         int z = fa[y];
 92         while(y != g){
 93             if(z != g) {
 94                 (s[z][1] == y) ^ (s[y][1] == x)
 95                 ? rotate(x) : rotate(y);
 96             }
 97             rotate(x);
 98             y = fa[x]; /// space
 99             z = fa[y];
100         }
101         return;
102     }
103 
104     inline int getNbyR(int x) {
105         int p = root, t;
106         while(1) {
107             t = siz[s[p][0]];
108             if(t + 1 == x) {
109                 break;
110             }
111             if(t + 1 > x){
112                 p = s[p][0];
113             }
114             else if(t + 1 < x) {
115                 x -= (t + 1);
116                 p = s[p][1];
117             }
118         }
119         return p;
120     }
121 
122     inline int get(int l, int r) {
123         r += 2;
124         int p = getNbyR(l);
125         splay(p, 0);
126         p = getNbyR(r);
127         splay(p, root);
128         return s[p][0];
129     }
130 
131     inline int getmax(int l, int r) {
132         int p = get(l, r);
133         return small[p];
134     }
135 
136     void out(int p) {
137         if(s[p][0]) {
138             out(s[p][0]);
139         }
140         printf("%d ", val[p]);
141         if(s[p][1]) {
142             out(s[p][1]);
143         }
144         return;
145     }
146 }spt;
147 
148 int main() {
149     int n, m;
150     scanf("%d%d", &n, &m);
151     spt.s[2][0] = spt.build(1, n, 2);
152     spt.pushup(2);
153     spt.pushup(1);
154     for(int i = 1, x, y; i <= m; i++) {
155         scanf("%d%d", &x, &y);
156         printf("%d ", spt.getmax(x, y));
157     }
158     return 0;
159 }
洛谷P1816 区间最小值
  1 #include <cstdio>
  2 #define db printf("*")
  3 typedef long long LL;
  4 const int N = 100010;
  5 
  6 struct SplayTree {
  7     int fa[N], s[N][2], siz[N], tot, root;
  8     LL val[N], delta[N], sum[N];
  9     SplayTree() {
 10         tot = 2;
 11         fa[2] = 1;
 12         s[1][1] = 2;
 13         root = 1;
 14     }
 15 
 16     inline void pushup(int p) {
 17         siz[p] = siz[s[p][0]] + siz[s[p][1]] + 1;
 18         sum[p] = sum[s[p][0]] + sum[s[p][1]] + val[p];
 19         return;
 20     }
 21     inline void pushdown(int p) {
 22         if(!delta[p]) {
 23             return;
 24         }
 25         int d = delta[p];
 26         int ls = s[p][0], rs = s[p][1];
 27 
 28         delta[ls] += d;
 29         delta[rs] += d;
 30         sum[ls] += d * siz[ls];
 31         sum[rs] += d * siz[rs];
 32         val[ls] += d;
 33         val[rs] += d;
 34 
 35         delta[p] = 0;
 36         return;
 37     }
 38 
 39     int build(int l, int r, int f) {
 40         int p = ++tot;
 41         fa[p] = f;
 42         int mid = (l + r) >> 1;
 43         if(l < mid) {
 44             s[p][0] = build(l, mid - 1, p);
 45         }
 46         scanf("%lld", &val[p]);
 47         if(mid < r) {
 48             s[p][1] = build(mid + 1, r, p);
 49         }
 50         pushup(p);
 51         return p;
 52     }
 53 
 54     inline void rotate(int x) {
 55         int y = fa[x];
 56         int z = fa[y];
 57         pushdown(y);
 58         pushdown(x);
 59         bool f = s[y][1] == x;
 60 
 61         if(z) {
 62             s[z][s[z][1] == y] = x;
 63         }
 64         fa[x] = z;
 65         s[y][f] = s[x][!f];
 66         fa[s[x][!f]] = y;
 67         fa[y] = x;
 68         s[x][!f] = y;
 69 
 70         if(!z) {
 71             root = x;
 72         }
 73         pushup(y);
 74         pushup(x);
 75         return;
 76     }
 77     inline void splay(int x, int g) {
 78         int y = fa[x];
 79         int z = fa[y];
 80         while(y != g) {
 81             if(z != g) {
 82                 (s[y][1] == x) ^ (s[z][1] == y) ?
 83                 rotate(x) : rotate(y);
 84             }
 85             rotate(x);
 86             y = fa[x]; /// !!! ERROR
 87             z = fa[y];
 88         }
 89         return;
 90     }
 91 
 92     int getNbyR(int x) {
 93         int p = root;
 94         while(1) {
 95             int t = siz[s[p][0]];
 96             if(t >= x) {
 97                 p = s[p][0];
 98             }
 99             else if(t + 1 == x) {
100                 break;
101             }
102             else {
103                 x -= (t + 1);
104                 p = s[p][1];
105             }
106         }
107         return p;
108     }
109     inline int get(int l, int r) {
110         int p = getNbyR(l);
111         splay(p, 0);
112         p = getNbyR(r + 2);
113         splay(p, root);
114         return p;
115     }
116 
117     inline void add(int l, int r, LL v) {
118         int p = get(l, r);
119         p = s[p][0];
120         sum[p] += v * siz[p];
121         val[p] += v;
122         delta[p] += v;
123         return;
124     }
125 
126     inline LL asksum(int l, int r) {
127         int p = get(l, r);
128         return sum[s[p][0]];
129     }
130 }spt;
131 
132 int main() {
133     int n, m;
134     scanf("%d%d", &n, &m);
135     spt.s[2][0] = spt.build(1, n, 2);
136     spt.pushup(2);
137     spt.pushup(1);
138 
139     int f, x, y, z;
140     while(m--) {
141         scanf("%d", &f);
142         if(f == 1) {
143             scanf("%d%d%d", &x, &y, &z);
144             spt.add(x, y, z);
145         }
146         else {
147             scanf("%d%d", &x, &y);
148             printf("%lld\n", spt.asksum(x, y));
149         }
150     }
151 
152     return 0;
153 }
洛谷P3372 区间加

 接下来是一些例题:

(此处应有例题)

朝鲜树/替罪羊树:

不维护,基于重构。

当这棵树不平衡到一定程度之后就扔了,重新建一个完全二叉树。

Treap:

Tree + Heap,基于随机。

给每个节点放一个随机的dat值,要使val满足BST性质的同时dat满足堆性质。

SBT:

Size Balanced Tree。由于有maintain它十分的平衡。

红黑树:

效率极高,代码极难,c++模板用树。

AVl:

???

... ...

posted @ 2018-06-24 13:20  garage  阅读(152)  评论(0编辑  收藏  举报