zoukankan      html  css  js  c++  java
  • [Bzoj3224][Tyvj1728] 普通平衡树(splay/无旋Treap)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3224

    平衡树入门题,学习学习。

    splay(学习yyb巨佬)

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 typedef long long ll;
      4 const int maxn = 500100;
      5 const int INF = 1e9;
      6 inline void read(int &n) {
      7     register int x = 0, t = 1;
      8     register char ch = getchar();
      9     while (ch != '-' && (ch<'0' || ch>'9'))ch = getchar();
     10     if (ch == '-') { t = -1; ch = getchar(); }
     11     while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
     12     n = x * t;
     13 }
     14 int root, len;
     15 struct node {
     16     int fa;//节点的父节点
     17     int siz;//节点的子树数量
     18     int ch[2];//节点的左(0)子节点和右(1)子节点
     19     int val;//节点的值
     20     int num;//节点的值的数量
     21 }a[maxn];
     22 inline void pushup(int x) {//更新当前节点的子树//当前子树的大小是左子树大小加上右子树大小当前当前节点个数
     23     a[x].siz = a[a[x].ch[0]].siz + a[a[x].ch[1]].siz + a[x].num;
     24 }
     25 inline void rotate(int x) {//旋转操作//将x旋转到x的父亲的位置
     26     int y = a[x].fa;//y是x的父节点
     27     int z = a[y].fa;//z是x的祖父节点
     28     int k = (a[y].ch[1] == x);//求x是y的左(0)还是右(1)节点
     29     a[z].ch[a[z].ch[1] == y] = x;//求y是z的左(0)还是右(1)节点,同时将x放在该位置
     30     a[x].fa = z;//修改x的父节点
     31     a[y].ch[k] = a[x].ch[k ^ 1];//把x的儿子给y
     32     a[a[x].ch[k ^ 1]].fa = y;//更新父节点为y
     33     a[x].ch[k ^ 1] = y;//y变为x的子节点
     34     a[y].fa = x;//y的父亲更新为x
     35     pushup(y), pushup(x);//更新y和x的子节点数量
     36 }
     37 inline void splay(int x, int goal) {//将x旋转为goal的子节点
     38     while (a[x].fa != goal) {
     39         int y = a[x].fa;
     40         int z = a[y].fa;
     41         if (z != goal)
     42             (a[y].ch[1] == x) ^ (a[z].ch[1] == y) ? rotate(x) : rotate(y);
     43         //如果x和y同为左儿子或者右儿子先旋转y
     44         //如果x和y不同为左儿子或者右儿子先旋转x
     45         //如果不双旋的话,旋转完成之后树的结构不会变化
     46         rotate(x);
     47     }
     48     if (goal == 0)
     49         root = x;
     50 }
     51 inline void insert(int x) {
     52     int now = root, fa = 0;//当前节点now和now的父节点fa
     53     while (now&&a[now].val != x) {//当now存在并且没有移动到当前的值
     54         fa = now;//父节点变为now
     55         now = a[now].ch[x > a[now].val];//x大于当前位置则now向右,否则now向左
     56     }
     57     if (now)//这个值出现过
     58         a[now].num++;//值增加
     59     else {//这个值第一次出现,要新建一个节点来存放
     60         now = ++len;
     61         if (fa)//父节点不是根节点(0)
     62             a[fa].ch[x > a[fa].val] = now;
     63         //初始化节点
     64         a[now].ch[0] = a[now].ch[1] = 0;
     65         a[now].siz = 1;
     66         a[now].num = 1;
     67         a[now].fa = fa;
     68         a[now].val = x;
     69     }
     70     splay(now, 0);
     71 }
     72 inline void  Find(int x) {//查找x的位置,并将其旋转到根节点
     73     int now = root;
     74     if (!now)return;//数为空
     75     while (a[now].ch[x > a[now].val] && x != a[now].val)////当存在儿子并且当前位置的值不等于x
     76         now = a[now].ch[x > a[now].val];
     77     splay(now, 0);//把当前位置旋转到根节点
     78 }
     79 inline int Next(int x, int flag) {//查找x的前驱(0)或者后继(1)
     80     Find(x);
     81     int now = root;
     82     if (a[now].val > x&&flag)return now;//如果当前节点的值大于x并且要查找的是后继
     83     if (a[now].val < x && !flag)return now;//如果当前节点的值小于x并且要查找的是前驱
     84     now = a[now].ch[flag];//查找后继的话在右儿子上找,前驱在左儿子上找
     85     while (a[now].ch[flag ^ 1])now = a[now].ch[flag ^ 1];
     86     return now;
     87 }
     88 inline void Delete(int x) {//删除一个x
     89     int last = Next(x, 0);//查找x的前驱
     90     int next = Next(x, 1);//查找x的后继
     91     splay(last, 0), splay(next, last);
     92     //将前驱旋转到根节点,后继旋转到根节点下面
     93     //很明显,此时后继是前驱的右儿子,x是后继的左儿子,并且x是叶子节点
     94     int now = a[next].ch[0];//后继的左儿子,也就是x
     95     if (a[now].num > 1) {//超过一个就删除一个
     96         a[now].num--;
     97         splay(now, 0);
     98     }
     99     else
    100         a[next].ch[0] = 0;//直接删除
    101 
    102 }
    103 inline int kth(int k) {//查找第k小的数
    104     int now = root;
    105     if (a[now].siz < k)
    106         return 0;
    107     while (1) {
    108         int y = a[now].ch[0];//y是左儿子
    109         if (k > a[y].siz + a[now].num) {//如果排名比左儿子的大小和当前节点的数量要大
    110             k -= a[y].siz + a[now].num;//排名减小
    111             now = a[now].ch[1];//定在右儿子上找
    112         }
    113         else {
    114             if (k <= a[y].siz)
    115                 now = y;
    116             else
    117                 return a[now].val;
    118         }
    119     }
    120 }
    121 int main() {
    122     int n;
    123     read(n);
    124     root = 0, len = 0;
    125     insert(1000000000);
    126     insert(-1000000000);
    127     while (n--) {
    128         int q, x;
    129         read(q), read(x);
    130         if (q == 1)
    131             insert(x);
    132         else if (q == 2)
    133             Delete(x);
    134         else if (q == 3) {
    135             Find(x);
    136             printf("%d
    ", a[a[root].ch[0]].siz);
    137         }
    138         else if (q == 4)
    139             printf("%d
    ", kth(x + 1));
    140         else if (q == 5)
    141             printf("%d
    ", a[Next(x, 0)].val);
    142         else if (q == 6)
    143             printf("%d
    ", a[Next(x, 1)].val);
    144     }
    145 }

    无旋Treap(学习fzszkl巨佬)

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 typedef long long ll;
      4 const int maxn = 1e5 + 10;
      5 int Siz[maxn], ls[maxn], rs[maxn], val[maxn], pos[maxn], root;
      6 int cnt;
      7 int send = 19260817;
      8 inline int Rand() {
      9     send ^= send << 7;
     10     send ^= send >> 5;
     11     send ^= send << 13;
     12     return send;
     13 }
     14 inline int New(int x) {
     15     cnt++;
     16     pos[cnt] = Rand();
     17     Siz[cnt] = 1;
     18     val[cnt] = x;
     19     return cnt;
     20 }
     21 inline void up(int x) {
     22     Siz[x] = Siz[ls[x]] + Siz[rs[x]] + 1;
     23 }
     24 void split_size(int x, int siz, int &A, int &B) {
     25     if (x == 0)return (void)(A = B = 0);
     26     if (siz <= Siz[ls[x]])
     27         B = x, split_size(ls[x], siz, A, ls[x]);
     28     else
     29         A = x, split_size(rs[x], siz - Siz[ls[x]] - 1, rs[x], B);
     30     up(x);
     31 }
     32 void split_val(int x, int v, int &A, int &B) {
     33     if (x == 0)return (void)(A = B = 0);
     34     if (v < val[x])
     35         B = x, split_val(ls[x], v, A, ls[x]);
     36     else
     37         A = x, split_val(rs[x], v, rs[x], B);
     38     up(x);
     39 }
     40 int Merge(int A, int B) {
     41     if (A == 0 || B == 0)return A | B;
     42     int ans;
     43     if (pos[A] > pos[B])ans = A, rs[A] = Merge(rs[A], B);
     44     else ans = B, ls[B] = Merge(A, ls[B]);
     45     up(ans);
     46     return ans;
     47 }
     48 void dfs(int x) {
     49     if (x == 0)
     50         return;
     51     printf("%d ", x);
     52     dfs(ls[x]);
     53     dfs(rs[x]);
     54 }
     55 void insert(int x) {
     56     int A, B;
     57     split_val(root, x - 1, A, B);
     58     root = Merge(Merge(A, New(x)), B);
     59 }
     60 void Delete(int x) {
     61     int A, B, C, D;
     62     split_val(root, x - 1, A, B);
     63     split_size(B, 1, C, D);//C就是删除的节点
     64     root = Merge(A, D);
     65 }
     66 int Rank(int x) {//查x的排名
     67     int A, B, ans;
     68     split_val(root, x - 1, A, B);
     69     ans = Siz[A] + 1;
     70     root = Merge(A, B);
     71     return ans;
     72 }
     73 int getR(int x) {//查第x名是什么
     74     int A, B, C, D, ans;
     75     split_size(root, x - 1, A, B);
     76     split_size(B, 1, C, D);
     77     ans = val[C];
     78     Merge(Merge(A, C), D);
     79     return ans;
     80 }
     81 int last(int x) {
     82     int A, B, C, D, ans;
     83     split_val(root, x - 1, A, B);
     84     split_size(A, Siz[A] - 1, C, D);
     85     ans = val[D];
     86     Merge(Merge(C, D), B);
     87     return ans;
     88 }
     89 int Next(int x) {
     90     int A, B, C, D, Ans;
     91     split_val(root, x, A, B);
     92     split_size(B, 1, C, D);
     93     Ans = val[C];
     94     root = Merge(Merge(A, C), D);
     95     return Ans;
     96 }
     97 int main() {
     98     int n;
     99     scanf("%d", &n);
    100     while (n--) {
    101         int opt, x;
    102         scanf("%d%d", &opt, &x);
    103         if (opt == 1)
    104             insert(x);
    105         else if (opt == 2)
    106             Delete(x);
    107         else if (opt == 3)
    108             printf("%d
    ", Rank(x));
    109         else if (opt == 4)
    110             printf("%d
    ", getR(x));
    111         else if (opt == 5)
    112             printf("%d
    ", last(x));
    113         else if (opt == 6)
    114             printf("%d
    ", Next(x));
    115     }
    116     return 0;
    117 }
  • 相关阅读:
    青瓷qici
    青瓷qici
    青瓷qici
    青瓷引擎_珍膳小游戏_巧妇有好米来做煮
    2013年12月30日 星期一 谷歌、百度地图拽取
    不懂网络知识,测试工程师真的能走得很远么
    测试和开发之间的博弈--没有硝烟的战争
    docker命令每次需要sudo操作解决方案
    Ubuntu 18.04安装Docker CE + NVIDIA-Docker
    windos10下安装ubuntu18双系统
  • 原文地址:https://www.cnblogs.com/sainsist/p/11119402.html
Copyright © 2011-2022 走看看