zoukankan      html  css  js  c++  java
  • [BZOJ 3224]Tyvj 1728 普通平衡树

    Description

    您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
    1. 插入x数
    2. 删除x数(若有多个相同的数,因只删除一个)
    3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
    4. 查询排名为x的数
    5. 求x的前驱(前驱定义为小于x,且最大的数)
    6. 求x的后继(后继定义为大于x,且最小的数)

    Input

    第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

    Output

    对于操作3,4,5,6每行输出一个数,表示对应答案

    Sample Input

    10
    1 106465
    4 1
    1 317721
    1 460929
    1 644985
    1 84185
    1 89851
    6 81968
    1 492737
    5 493598

    Sample Output

    106465
    84185
    492737

    HINT

    1.n的数据范围:n<=100000
    2.每个数的数据范围:[-2e9,2e9]

    题解

    作为一个模板题放在这里,准备写4个常用的平衡树。算是个坑...

    1 Splay

    1.1 插入操作

    一般平衡树的操作,不多赘述。

    1.2 删除操作

    我们考虑删除数$x$:我们将$x$的前驱和后继找到。两个找到之后再将前驱通过$splay$操作旋到根,再将后继旋成前驱的儿子,删除后继的左儿子即可。
    显然能够保证后继的左儿子只有一个。
    至于为什么要前驱和后继都找到之后再旋转,是因为查找的时候会将其他的节点旋转到根。

    1.3 查询名次

    我们通过维护子树大小来实现这一功能。
    某个数的名次其实就是当它旋转到根的时候左子树的大小+1。
    我们对于每次插入操作,删除操作,$rotate$操作都要更新名次。

    1.4 查询Kth数

    递归实现。
    若左子树大小+1 <= 查询名次 <= 左子树大小+根节点数个数,结果就是当前数;
    若查询名次 <= 左子树大小+1,递归查询左子树;
    若查询名次 >= 左子树大小+根节点数个数,将查询名次-=左子树大小+根节点数个数,递归查询右子树。

    1.5 查找前驱

    通过$find$操作,找到“接近”这个数的数的位置。
    为什么是“接近”,是因为可能$splay$中可能不存在这个数,不存在的话我们就假想最后停在的节点就是这个数。
    将其旋到根。判断这个数与根节点的数的关系,若小于(即不存在查询的数)显然这个数就是前驱。
    若非,就查询其左子树“最靠右的那个数”。

    1.6 查找后继

    和查找前驱类似。

      1 //It is made by Awson on 2017.11.28
      2 #include <map>
      3 #include <set>
      4 #include <cmath>
      5 #include <ctime>
      6 #include <queue>
      7 #include <stack>
      8 #include <cstdio>
      9 #include <string>
     10 #include <vector>
     11 #include <cstdlib>
     12 #include <cstring>
     13 #include <iostream>
     14 #include <algorithm>
     15 #define LL long long
     16 #define Max(a, b) ((a) > (b) ? (a) : (b))
     17 #define Min(a, b) ((a) < (b) ? (a) : (b))
     18 using namespace std;
     19 const int N = 100000;
     20 const int INF = ~0u>>1;
     21 
     22 struct Splay_tree {
     23     int pre[N+5], ch[N+5][2], key[N+5], size[N+5], cnt[N+5], tot, root;
     24     queue<int>mem;
     25     void newnode(int &o, int keyy, int fa) {
     26     if (!mem.empty()) o = mem.front(), mem.pop();
     27     else o = ++tot;
     28     pre[o] = fa, ch[o][0] = ch[o][1] = 0;
     29     key[o] = keyy, cnt[o] = size[o] = 1;
     30     }
     31     void pushup(int o) {
     32     size[o] = size[ch[o][0]]+size[ch[o][1]]+cnt[o];
     33     }
     34     void rotate(int o, int kind) {
     35     int p = pre[o];
     36     ch[p][!kind] = ch[o][kind], pre[ch[o][kind]] = p;
     37     ch[pre[p]][ch[pre[p]][1] == p] = o, pre[o] = pre[p];
     38     ch[o][kind] = p, pre[p] = o;
     39     pushup(p), pushup(o);
     40     }
     41     void splay(int o, int goal) {
     42     while (pre[o] != goal) {
     43         if (pre[pre[o]] == goal) rotate(o, ch[pre[o]][0] == o);
     44         else {
     45         int p = pre[o], kind = ch[pre[p]][0] == p;
     46         if (ch[p][kind] == o) rotate(o, !kind), rotate(o, kind);
     47         else rotate(p, kind), rotate(o, kind);
     48         }
     49     }
     50     if (goal == 0) root = o;
     51     }
     52     void insert(int &o, int keyy, int fa) {
     53     if (o == 0) {
     54         newnode(o, keyy, fa); splay(o, 0); return;
     55     }
     56     size[o]++;
     57     if (key[o] == keyy) {
     58         cnt[o]++; splay(o, 0); return;
     59     }
     60     insert(ch[o][keyy > key[o]], keyy, o);
     61     }
     62     void find(int o, int keyy) {
     63     if (o == 0) return;
     64     if (key[o] == keyy) {
     65         splay(o, 0); return;
     66     }
     67     if (ch[o][keyy > key[o]]) find(ch[o][keyy > key[o]], keyy);
     68     else splay(o, 0);
     69     }
     70     int get_las(int keyy) {
     71     find(root, keyy);
     72     if (keyy > key[root]) return root;
     73     int u = ch[root][0];
     74     while (ch[u][1]) u = ch[u][1];
     75     return u;
     76     }
     77     int get_nex(int keyy) {
     78     find(root, keyy);
     79     if (keyy < key[root]) return root;
     80     int u = ch[root][1];
     81     while (ch[u][0]) u = ch[u][0];
     82     return u;
     83     }
     84     void delet(int keyy) {
     85     int las = get_las(keyy);
     86     int nex = get_nex(keyy);
     87     splay(las, 0), splay(nex, las);
     88     size[las]--, size[nex]--;
     89     if (cnt[ch[nex][0]] > 1) {
     90         cnt[ch[nex][0]]--; size[ch[nex][0]]--;
     91         splay(ch[nex][0], 0);
     92     }else {
     93         mem.push(ch[nex][0]);
     94         ch[nex][0] = 0;
     95     }
     96     }
     97     int Kth(int o, int rest) {
     98     if (rest >= size[ch[o][0]]+1 && rest <= size[ch[o][0]]+cnt[o]) return o;
     99     if (rest > size[ch[o][0]]+cnt[o]) return Kth(ch[o][1], rest-size[ch[o][0]]-cnt[o]);
    100     return Kth(ch[o][0], rest);
    101     }
    102 }S;
    103 int n, opt, x;
    104 
    105 void work() {
    106     S.insert(S.root, INF, 0);
    107     S.insert(S.root, -INF, 0);
    108     scanf("%d", &n);
    109     while (n--) {
    110     scanf("%d%d", &opt, &x);
    111     if (opt == 1) S.insert(S.root, x, 0);
    112     else if (opt == 2) S.delet(x);
    113     else if (opt == 3) {
    114         S.find(S.root, x);
    115         printf("%d
    ", S.size[S.ch[S.root][0]]);
    116     }else if (opt == 4) printf("%d
    ", S.key[S.Kth(S.root, x+1)]);
    117     else if (opt == 5) printf("%d
    ", S.key[S.get_las(x)]);
    118     else if (opt == 6) printf("%d
    ", S.key[S.get_nex(x)]);
    119     }
    120 }
    121 int main() {
    122     work();
    123     return 0;
    124 }
    Splay

    2 替罪羊树

    替罪羊树的平衡是基于子树大小平衡的。

    对于树中的结点$o$若存在$size[o]*alpha >= size[ch[o][0]]$ 且 $size[o]*alpha >= size[ch[o][1]]$,则对于以$o$为根的子树是平衡的。若不平衡直接将子树暴力拍平重建。

      1 //It is made by Awson on 2017.12.8
      2 #include <map>
      3 #include <set>
      4 #include <cmath>
      5 #include <ctime>
      6 #include <queue>
      7 #include <stack>
      8 #include <cstdio>
      9 #include <string>
     10 #include <vector>
     11 #include <cstdlib>
     12 #include <cstring>
     13 #include <iostream>
     14 #include <algorithm>
     15 #define LL long long
     16 #define Max(a, b) ((a) > (b) ? (a) : (b))
     17 #define Min(a, b) ((a) < (b) ? (a) : (b))
     18 using namespace std;
     19 const int N = 100000;
     20 const int INF = ~0u>>1;
     21 const double alpha = 0.75;
     22 
     23 struct Scapegoat_tree {
     24     int size[N+5], ch[N+5][2], key[N+5], del[N+5], pre[N+5], root, tot, tmp[N+5];
     25     queue<int>mem;
     26     void newnode(int &o, int keyy, int fa) {
     27     if (!mem.empty()) o = mem.front(), mem.pop();
     28     else o = ++tot;
     29     size[o] = 1, ch[o][0] = ch[o][1] = del[o] = 0;
     30     key[o] = keyy, pre[o] = fa;
     31     }
     32     bool balance(int o) {
     33     return size[o]*alpha >= size[ch[o][0]] && size[o]*alpha >= size[ch[o][1]];
     34     }
     35     void pushup(int o) {
     36     size[o] = size[ch[o][0]]+size[ch[o][1]]+(!del[o]);
     37     }
     38     void travel(int o, int &pos) {
     39     if (ch[o][0]) travel(ch[o][0], pos);
     40     if (!del[o]) tmp[++pos] = o;
     41     else mem.push(o);
     42     if (ch[o][1]) travel(ch[o][1], pos);
     43     }
     44     int device(int fa, int l, int r) {
     45     if (l > r) return 0;
     46     int mid = (l+r)>>1, o = tmp[mid];
     47     ch[o][0] = device(o, l, mid-1);
     48     ch[o][1] = device(o, mid+1, r);
     49     pre[o] = fa; size[o] = 1;
     50     pushup(o);
     51     return o;
     52     }
     53     void rebuild(int o) {
     54     int pos = 0; travel(o, pos);
     55     if (root == o) root = device(0, 1, pos);
     56     else {
     57         int t = ch[pre[o]][1] == o;
     58         ch[pre[o]][t] = device(pre[o], 1, pos);
     59     }
     60     }
     61     int Insert(int &o, int keyy, int fa) {
     62     if (!o) {
     63         newnode(o, keyy, fa); return 0;
     64     }
     65     size[o]++;
     66     int p = Insert(ch[o][keyy >= key[o]], keyy, o);
     67     if (!balance(o)) p = o;
     68     return p;
     69     }
     70     void insert(int &o, int keyy, int fa) {
     71     int x = Insert(o, keyy, fa); if (x) rebuild(x);
     72     }
     73     int rank(int o, int keyy) {
     74     if (!o) return 1;
     75     if (key[o] < keyy) return size[ch[o][0]]+(!del[o])+rank(ch[o][1], keyy);
     76     else return rank(ch[o][0], keyy);
     77     }
     78     int Erase(int o, int rank) {
     79     size[o]--;
     80     if (!del[o] && size[ch[o][0]]+(!del[o]) == rank) {
     81         del[o] = 1; return 0;
     82     }
     83     int p;
     84     if (size[ch[o][0]] >= rank) p = Erase(ch[o][0], rank);
     85     else p = Erase(ch[o][1], rank-(size[ch[o][0]]+(!del[o])));
     86     if (!balance(o)) p = o;
     87     return p;
     88     }
     89     void erase(int o, int keyy) {
     90     int rk = rank(o, keyy);
     91     int x = Erase(o, rk); if (x) rebuild(x);
     92     }
     93     int get_num(int o, int rank) {
     94     if (!del[o] && size[ch[o][0]]+(!del[o]) == rank) return key[o];
     95     if (size[ch[o][0]] >= rank) return get_num(ch[o][0], rank);
     96     return get_num(ch[o][1], rank-(size[ch[o][0]]+(!del[o])));
     97     }
     98 }S;
     99 int n, opt, x;
    100 
    101 void work() {
    102     S.insert(S.root, INF, 0);
    103     S.insert(S.root, -INF, 0);
    104     scanf("%d", &n);
    105     while (n--) {
    106     scanf("%d%d", &opt, &x);
    107     if (opt == 1) S.insert(S.root, x, 0);
    108     else if (opt == 2) S.erase(S.root, x);
    109     else if (opt == 3) printf("%d
    ", S.rank(S.root, x)-1);
    110     else if (opt == 4) printf("%d
    ", S.get_num(S.root, x+1));
    111     else if (opt == 5) printf("%d
    ", S.get_num(S.root, S.rank(S.root, x)-1));
    112     else printf("%d
    ", S.get_num(S.root, S.rank(S.root, x+1)));
    113     }
    114 }
    115 int main() {
    116     work();
    117     return 0;
    118 }
    Scapegoat

    3 Treap

    $Treap$的平衡是基于堆性质的。它的$key$值满足$BST$的性质,平衡参数$lev$满足堆性质。

      1 //It is made by Awson on 2017.12.11
      2 #include <map>
      3 #include <set>
      4 #include <cmath>
      5 #include <ctime>
      6 #include <queue>
      7 #include <stack>
      8 #include <cstdio>
      9 #include <string>
     10 #include <vector>
     11 #include <cstdlib>
     12 #include <cstring>
     13 #include <iostream>
     14 #include <algorithm>
     15 #define LL long long
     16 #define Max(a, b) ((a) > (b) ? (a) : (b))
     17 #define Min(a, b) ((a) < (b) ? (a) : (b))
     18 using namespace std;
     19 const int N = 100000;
     20 const int INF = ~0u>>1;
     21 
     22 struct Treap {
     23     int ch[N+5][2], lev[N+5], size[N+5], cnt[N+5], key[N+5], tot, root;
     24     queue<int>mem;
     25     void newnode(int &o, int keyy) {
     26     if (!mem.empty()) o = mem.front(), mem.pop();
     27     else o = ++tot;
     28     ch[o][0] = ch[o][1] = 0;
     29     cnt[o] = size[o] = 1;
     30     key[o] = keyy, lev[o] = rand();
     31     }
     32     void pushup(int o) {
     33     size[o] = size[ch[o][0]]+size[ch[o][1]]+cnt[o];
     34     }
     35     void rotate(int &o, int kind) {
     36     int x = ch[o][!kind];
     37     ch[o][!kind] = ch[x][kind];
     38     ch[x][kind] = o;
     39     o = x;
     40     }
     41     void insert(int &o, int keyy) {
     42     if (!o) {
     43         newnode(o, keyy); return;
     44     }
     45     size[o]++;
     46     if (key[o] == keyy) {
     47         cnt[o]++; return;
     48     }
     49     int kind = keyy >= key[o];
     50     insert(ch[o][kind], keyy);
     51     if (lev[ch[o][kind]] > lev[o]) {
     52         rotate(o, !kind); pushup(ch[o][!kind]), pushup(o);
     53     }
     54     }
     55     void delet(int &o, int keyy) {
     56     if (key[o] == keyy) {
     57         if (cnt[o] > 1) {
     58         size[o]--; cnt[o]--; return;
     59         }else {
     60         if (ch[o][0] && ch[o][1]) {
     61             int kind = lev[ch[o][0]] > lev[ch[o][1]];
     62             rotate(o, kind); pushup(ch[o][kind]), pushup(o);
     63             size[o]--;
     64             delet(ch[o][kind], keyy);
     65         }else {
     66             int kind = (bool)ch[o][1];
     67             mem.push(o);
     68             o = ch[o][kind];
     69         }
     70         }
     71     }else {
     72         size[o]--; delet(ch[o][keyy >= key[o]], keyy);
     73     }
     74     }
     75     int rank(int o, int keyy) {
     76     if (key[o] == keyy) return size[ch[o][0]]+1;
     77     if (key[o] < keyy) return size[ch[o][0]]+cnt[o]+rank(ch[o][1], keyy);
     78     return rank(ch[o][0], keyy);
     79     }
     80     int get_num(int o, int rk) {
     81     if (size[ch[o][0]]+1 <= rk && rk <= size[ch[o][0]]+cnt[o]) return key[o];
     82     if (rk <= size[ch[o][0]]) return get_num(ch[o][0], rk);
     83     return get_num(ch[o][1], rk-size[ch[o][0]]-cnt[o]);
     84     }
     85     int get_pre(int o, int keyy, int ans) {
     86     if (!o) return ans;
     87     if (key[o] >= keyy) return get_pre(ch[o][0], keyy, ans);
     88     ans = Max(ans, key[o]);
     89     return get_pre(ch[o][1], keyy, ans);
     90     }
     91     int get_nex(int o, int keyy, int ans) {
     92     if (!o) return ans;
     93     if (key[o] <= keyy) return get_nex(ch[o][1], keyy, ans);
     94     ans = Min(ans, key[o]);
     95     return get_nex(ch[o][0], keyy, ans);
     96     }
     97 }T;
     98 int n, opt, x;
     99 
    100 void work() {
    101     srand(time(0));
    102     scanf("%d", &n);
    103     while (n--) {
    104     scanf("%d%d", &opt, &x);
    105     if (opt == 1) T.insert(T.root, x);
    106     else if (opt == 2) T.delet(T.root, x);
    107     else if (opt == 3) printf("%d
    ", T.rank(T.root, x));
    108     else if (opt == 4) printf("%d
    ", T.get_num(T.root, x));
    109     else if (opt == 5) printf("%d
    ", T.get_pre(T.root, x, -INF));
    110     else printf("%d
    ", T.get_nex(T.root, x, INF));
    111     }
    112 }
    113 int main() {
    114     work();
    115     return 0;
    116 }
    Treap

    4 fhq_Treap

    一般的$Treap$的自平衡是依赖于$rotate$操作实现的,而无旋$Treap$则是依靠$split$和$merge$两个操作实现自平衡。

    其主要的思想就是将一棵$Treap$分成多个。再将多个$Treap$合并。

    坑终于填完了...

      1 //It is made by Awson on 2017.12.15
      2 #include <map>
      3 #include <set>
      4 #include <cmath>
      5 #include <ctime>
      6 #include <queue>
      7 #include <stack>
      8 #include <cstdio>
      9 #include <string>
     10 #include <vector>
     11 #include <cstdlib>
     12 #include <cstring>
     13 #include <iostream>
     14 #include <algorithm>
     15 #define LL long long
     16 #define Max(a, b) ((a) > (b) ? (a) : (b))
     17 #define Min(a, b) ((a) < (b) ? (a) : (b))
     18 using namespace std;
     19 const int N = 100000;
     20 const int INF = ~0u>>1;
     21 
     22 struct fhq_Treap {
     23     int ch[N+5][2], lev[N+5], size[N+5], key[N+5], tot, root;
     24     queue<int>mem;
     25     int newnode(int keyy) {
     26     int o;
     27     if (!mem.empty()) o = mem.front(), mem.pop();
     28     else o = ++tot;
     29     ch[o][0] = ch[o][1] = 0;
     30     size[o] = 1;
     31     key[o] = keyy, lev[o] = rand();
     32     return o;
     33     }
     34     void pushup(int o) {
     35     size[o] = size[ch[o][0]]+size[ch[o][1]]+1;
     36     }
     37     void split(int o, int keyy, int &x, int &y) {
     38     if (!o) x = y = 0;
     39     else {
     40         if (key[o] <= keyy) x = o, split(ch[o][1], keyy, ch[o][1], y);
     41         else y = o, split(ch[o][0], keyy, x, ch[o][0]);
     42         pushup(o);
     43     }
     44     }
     45     int merge(int x, int y) {
     46     if (!x || !y) return x+y;
     47     if (lev[x] < lev[y]) {
     48         ch[x][1] = merge(ch[x][1], y);
     49         pushup(x); return x;
     50     }else {
     51         ch[y][0] = merge(x, ch[y][0]);
     52         pushup(y); return y;
     53     }
     54     }
     55     void insert(int keyy) {
     56     int r1, r2; split(root, keyy, r1, r2);
     57     root = merge(merge(r1, newnode(keyy)), r2);
     58     }
     59     void delet(int keyy) {
     60     int r1, r2, r3; split(root, keyy-1, r1, r2);
     61     split(r2, keyy, r2, r3);
     62     mem.push(r2);
     63     r2 = merge(ch[r2][0], ch[r2][1]);
     64     root = merge(merge(r1, r2), r3);
     65     }
     66     int rank(int keyy) {
     67     int r1, r2; split(root, keyy-1, r1, r2);
     68     int ans = size[r1]+1;
     69     root = merge(r1, r2);
     70     return ans;
     71     }
     72     int get_num(int o, int rk) {
     73     if (size[ch[o][0]]+1 == rk) return key[o];
     74     if (size[ch[o][0]] >= rk) return get_num(ch[o][0], rk);
     75     return get_num(ch[o][1], rk-1-size[ch[o][0]]);
     76     }
     77     int get_pre(int keyy) {
     78     int r1, r2; split(root, keyy-1, r1, r2);
     79     int o = r1;
     80     while (ch[o][1]) o = ch[o][1];
     81     int ans = key[o];
     82     root = merge(r1, r2);
     83     return ans;
     84     }
     85     int get_nex(int keyy) {
     86     int r1, r2; split(root, keyy, r1, r2);
     87     int o = r2;
     88     while (ch[o][0]) o = ch[o][0];
     89     int ans = key[o];
     90     root = merge(r1, r2);
     91     return ans;
     92     }
     93 }T;
     94 int n, opt, x;
     95 
     96 void work() {
     97     srand(time(0));
     98     scanf("%d", &n);
     99     while (n--) {
    100     scanf("%d%d", &opt, &x);
    101     if (opt == 1) T.insert(x);
    102     else if (opt == 2) T.delet(x);
    103     else if (opt == 3) printf("%d
    ", T.rank(x));
    104     else if (opt == 4) printf("%d
    ", T.get_num(T.root, x));
    105     else if (opt == 5) printf("%d
    ", T.get_pre(x));
    106     else printf("%d
    ", T.get_nex(x));
    107     }
    108 }
    109 int main() {
    110     work();
    111     return 0;
    112 }
    fhq_Treap
  • 相关阅读:
    Modern C++ Course [Lecture 3] {CMake, Google Test, Namespaces, Classes}
    Modern C++ Course [Lecture 2] {Compilation, Debugging, Functions, Header/Source, Libraries, CMake}
    Modern C++ Course [Lecture 0] {Course Introduction and Hello World} & [Lecture 1] {Variables, Basic Types, Control Structures}
    RASPBERRY PI LINUX LESSON: From 29th to Final Project
    RASPBERRY PI LINUX LESSON: From 16th to 28th
    RASPBERRY PI LINUX LESSON: From 1st to 15th
    vscode spring boot配置文件application.properties不提示解决方式
    JdbcTemplate增删改查
    Spring注解@ConfigurationPropertie
    [转载]Spring下IOC容器和DI(依赖注入) @Bean及@Autowired
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7919884.html
Copyright © 2011-2022 走看看