zoukankan      html  css  js  c++  java
  • 替罪羊树模板

    LOJ #104.普通平衡树

      1 #include <bits/stdc++.h>
      2 
      3 const double alpha = 0.75;
      4 const int N = 1e5 + 233;
      5 int n;
      6 
      7 class ScapegoatTree {
      8 private:
      9     int cnt, tp;
     10     struct Node {
     11         Node *ch[2];
     12         int val, siz, exist, cnt;
     13         void pushup() {//上传
     14             siz = ch[0]->siz + ch[1]->siz + exist;
     15             cnt = ch[0]->cnt + ch[1]->cnt + 1;
     16         }
     17         bool is_bad() {//判断是否失衡
     18             return ch[0]->cnt > cnt * alpha + 5 || ch[1]->cnt > cnt * alpha + 5;
     19         }
     20     } *null, node[N], *root, *stk[N];
     21     Node *newnode(int val) {//新增一个节点
     22         Node *ret = node + (++cnt);
     23         ret->ch[0] = ret->ch[1] = null;
     24         ret->val = val;
     25         ret->siz = ret->cnt = ret->exist = 1;
     26         return ret;
     27     }
     28     void dfs(Node *p) {//把需要重构的点扔进栈里
     29         if (p == null) return;
     30         dfs(p->ch[0]);
     31         if (p->exist) stk[++tp] = p;
     32         dfs(p->ch[1]);
     33     }
     34     Node *divide(int l, int r) {//重构树,这样可以保证重构后的树中序遍历与原树相同
     35         if (r < l) return null;
     36         int mid = (l + r) >> 1;
     37         Node *ret = stk[mid];
     38         ret->ch[0] = divide(l, mid - 1);
     39         ret->ch[1] = divide(mid + 1, r);
     40         ret->pushup();
     41         return ret;
     42     }
     43     void rebuild(Node *&p) {
     44         tp = 0, dfs(p);
     45         p = divide(1, tp);
     46     }
     47     Node **_insert(Node *&p, int val) {//插入函数,同时返回一个指向最上坏点的指针
     48         if (p == null) {
     49             p = newnode(val);
     50             return &null;
     51         }
     52         if (p->val == val) {
     53             ++p->exist, p->pushup();
     54             return &null;
     55         }
     56         Node **ret;
     57         ++p->siz, ++p->cnt;
     58         if (val <= p->val) ret = _insert(p->ch[0], val);
     59         else ret = _insert(p->ch[1], val);
     60         if (p->is_bad()) return &p;
     61         p->cnt -= (*ret)->cnt - (*ret)->siz;
     62         return ret;
     63     }
     64     void _delete(Node *p, int val) {
     65         if (p->val == val) {
     66             --p->exist, p->pushup();
     67             return;
     68         }
     69         if (p->val < val) _delete(p->ch[1], val);
     70         else _delete(p->ch[0], val);
     71         p->pushup();
     72     }
     73 public:
     74     ScapegoatTree() {
     75         root = null = node;
     76         null->ch[0] = null->ch[1] = null;
     77         null->siz = null->cnt = null->val = null->exist = 0;
     78     }
     79     void insert(int val) {
     80         Node **p = _insert(root, val);
     81         if (p != &null) rebuild(*p);
     82     }
     83     void del(int val) {
     84         _delete(root, val);
     85         if (root->cnt * alpha > root->siz + 5) rebuild(root);
     86     }
     87     int get_rank(int val) {
     88         int ret = 0;
     89         Node *p = root;
     90         while (p != null) {
     91             if (p->val == val) return (ret + p->ch[0]->siz);
     92             if (p->val < val) {
     93                 ret += p->ch[0]->siz + p->exist;
     94                 p = p->ch[1];
     95             } else p = p->ch[0];
     96         }
     97         return ret;
     98     }
     99     int get_kth(int k) {
    100         Node *p = root;
    101         while (1) {
    102             if (p->ch[0]->siz >= k) p = p->ch[0];
    103             else if (p->ch[0]->siz + p->exist >= k) return p->val;
    104             else k -= p->ch[0]->siz + p->exist, p = p->ch[1];
    105         }
    106     }
    107 };
    108 
    109 signed main() {
    110     static ScapegoatTree *Kamome = new ScapegoatTree();
    111     scanf("%d", &n);
    112     for (int i = 1, op, x; i <= n; i++) {
    113         scanf("%d%d", &op, &x);
    114         switch (op) {
    115             case 1:
    116                 Kamome->insert(x);
    117                 break;
    118             case 2:
    119                 Kamome->del(x);
    120                 break;
    121             case 3:
    122                 printf("%d
    ", Kamome->get_rank(x) + 1);
    123                 break;
    124             case 4:
    125                 printf("%d
    ", Kamome->get_kth(x));
    126                 break;
    127             case 5:
    128                 printf("%d
    ", Kamome->get_kth(Kamome->get_rank(x)));
    129                 break;
    130             case 6:
    131                 printf("%d
    ", Kamome->get_kth(Kamome->get_rank(x + 1) + 1));
    132                 break;
    133         }
    134     }
    135     return 0;
    136 }

    ~~OOP赛高~~

    替罪羊树的主要思想:当一个子树不平衡就拍扁重建。虽然很暴力,但复杂度很科学。

    下面开始说注意点:

    1.null节点的加入:为了防止访问到空指针之类的需要大力分类讨论的谔谔玩意

    2._insert为什么是二维指针?:如果直接把二维指针都改成一维,我们可以得到一个指向坏点的指针p,但在它基础上重构是没有意义的。我们真正想要得到的不是坏点,是指向坏点的那个指针。使用二维指针可以保证我们找到指向坏点的指针。

    3.我们乘平衡因子时加的那玩意是干啥的?:防止节点较少时频繁重构,影响时间复杂度。

  • 相关阅读:
    RelativeLayout布局属性
    调整CodeIgniter错误报告级别
    php 报错 Cannot modify header information
    ScrollView中嵌套ListView
    机器学习索引贴(未分类)
    进程与线程
    并行程序
    缓存命中率
    启发式算法(Heuristic Algorithm)
    详解 LSTM
  • 原文地址:https://www.cnblogs.com/gekoo/p/11299627.html
Copyright © 2011-2022 走看看