博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
替罪羊树模板
阅读量:4318 次
发布时间:2019-06-06

本文共 4532 字,大约阅读时间需要 15 分钟。

LOJ #104.普通平衡树

1 #include 
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\n", Kamome->get_rank(x) + 1);123 break;124 case 4:125 printf("%d\n", Kamome->get_kth(x));126 break;127 case 5:128 printf("%d\n", Kamome->get_kth(Kamome->get_rank(x)));129 break;130 case 6:131 printf("%d\n", Kamome->get_kth(Kamome->get_rank(x + 1) + 1));132 break;133 }134 }135 return 0;136 }

~~OOP赛高~~

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

下面开始说注意点:

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

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

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

转载于:https://www.cnblogs.com/gekoo/p/11299627.html

你可能感兴趣的文章
thinksns 分页数据
查看>>
os模块
查看>>
LINQ to SQL vs. NHibernate
查看>>
基于Angular5和WebAPI的增删改查(一)
查看>>
windows 10 & Office 2016 安装
查看>>
最短路径(SP)问题相关算法与模板
查看>>
js算法之最常用的排序
查看>>
Python——交互式图形编程
查看>>
经典排序——希尔排序
查看>>
团队编程项目作业2-团队编程项目代码设计规范
查看>>
英特尔公司将停止910GL、915GL和915PL芯片组的生产
查看>>
团队编程项目作业2-团队编程项目开发环境搭建过程
查看>>
Stax解析XML示例代码
查看>>
cookie
查看>>
二级图片导航菜单
查看>>
<Using parquet with impala>
查看>>
07-Java 中的IO操作
查看>>
uclibc,eglibc,glibc之间的区别和联系【转】
查看>>
Java魔法堂:找外援的利器——Runtime.exec详解
查看>>
mysql数据库存放路径
查看>>