斜堆,非旋转treap,替罪羊树
2015-11-25 21:47
295 查看
一、斜堆
斜堆是一种可以合并的堆
节点信息:
主要利用merge函数
左偏树需要维护一个额外的信息,而斜堆每次强制swap(ch[0], ch[1]),以达到均摊$O(\log{n})$的效果
利用merge函数可以很容易地实现插入和删除
另外地,堆相对与平衡树来说无法删除一个元素,但是如果能够定位到这个指针就可以删除这个元素了,方法是存储父亲(merge里要维护一下fa)
删除一个元素时可以这样
当然,和其他树形结构一样,堆上也是可以维护tag的
加入maintain()函数和down()函数后就可以轻松实现这些功能,方法和其他树形结构类似
需要注意的是删除时要像自底向上的splay一样把从这个点到根的路径上的点都down()一遍,再调用del()函数
另外,由于堆高度是均摊$O(\log{n})$的,所以在处理集合信息时不需要额外的并查集,只需要每次暴力往上找到根来比较就能够做到$O(\log{n})$的复杂度了。
举一例带标记的题
View Code
打删除标记的还没想好前驱后继怎么求TAT
斜堆是一种可以合并的堆
节点信息:
struct Node { int v; Node *ch[2]; };
主要利用merge函数
Node *merge(Node *x, Node *y) { if(!x) return y; if(!y) return x; if(x->v < y->v) swap(x, y); x->ch[1] = merge(x->ch[1], y); return swap(x->ch[0], x->ch[1]), x; }
左偏树需要维护一个额外的信息,而斜堆每次强制swap(ch[0], ch[1]),以达到均摊$O(\log{n})$的效果
利用merge函数可以很容易地实现插入和删除
void ins(Node*& o, int x) { o = merge(o, new Node(x)); } void del(Node*& o) { o = merge(o->ch[0], o->ch[1]); }
另外地,堆相对与平衡树来说无法删除一个元素,但是如果能够定位到这个指针就可以删除这个元素了,方法是存储父亲(merge里要维护一下fa)
删除一个元素时可以这样
void del(Node*& o) { Node* p = o->fa; Node* r = merge(o->ch[0], o->ch[1]); r->fa = p; p->ch[p->ch[1] == o] = r; }
当然,和其他树形结构一样,堆上也是可以维护tag的
加入maintain()函数和down()函数后就可以轻松实现这些功能,方法和其他树形结构类似
需要注意的是删除时要像自底向上的splay一样把从这个点到根的路径上的点都down()一遍,再调用del()函数
另外,由于堆高度是均摊$O(\log{n})$的,所以在处理集合信息时不需要额外的并查集,只需要每次暴力往上找到根来比较就能够做到$O(\log{n})$的复杂度了。
举一例带标记的题
#include<iostream> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> using namespace std; void setIO(const string& a) { freopen((a+".in").c_str(), "r", stdin); freopen((a+".out").c_str(), "w", stdout); } #define szof(x) ((x) ? (x)->sz : 0) const int N = 200000 + 10; struct Node *pis; struct Node { int v, sz; Node *ch[2]; Node(int v = 0) : v(v) { sz = 1; ch[0] = ch[1] = 0; } void maintain() { sz = szof(ch[0]) + szof(ch[1]) + 1; } int cmp(int x) const { if(x == v) return -1; return x < v ? 0 : 1; } void *operator new(size_t) { return pis++; } }pool , *cache , *root; int tot = 0; void print(Node *o) { if(!o) return; print(o->ch[0]); cache[++tot] = o; print(o->ch[1]); } void rebuild(Node*& o, int l, int r) { if(l > r) return o = 0, void(); int mid = (l + r) >> 1; o = cache[mid]; rebuild(o->ch[0], l, mid - 1); rebuild(o->ch[1], mid + 1, r); o->maintain(); } void insert(Node*& o, int x) { if(!o) o = new Node(x); else { int d = o->cmp(x); if(d == -1) d = 0; insert(o->ch[d], x); } o->maintain(); } void scape(Node*& o, int x) { int d = o->cmp(x); if(d == -1) return; if(o->ch[d]->sz > o->sz * 0.75) { tot = 0; print(o); rebuild(o, 1, tot); }else scape(o->ch[d], x); } void insert(int x) { insert(root, x); scape(root, x); } void remove(Node*& o, int x) { int d = o->cmp(x); if(d == -1) { if(!o->ch[0] && !o->ch[1]) o = 0; else { tot = 0; print(o->ch[0]); print(o->ch[1]); rebuild(o, 1, tot); } }else remove(o->ch[d], x); if(o) o->maintain(); } int kth(Node *o, int k) { while(o) { int s = szof(o->ch[0]) + 1; if(s == k) return o->v; if(s < k) k -= s, o = o->ch[1]; else o = o->ch[0]; } return -1; } int rank(Node *o, int x) { int res = 0; for(int d; o; o = o->ch[d]) { d = o->cmp(x); if(d == 1) res += szof(o->ch[0]) + 1; if(d == -1) d = 0; } return res + 1; } int pre(Node *o, int x) { int res = -1; for(int d; o; o = o->ch[d]) { d = o->cmp(x); if(d == 1) res = o->v; if(d == -1) d = 0; } return res; } int suf(Node *o, int x) { int res = -1; for(int d; o; o = o->ch[d]) { d = o->cmp(x); if(d == 0) res = o->v; if(d == -1) d = 1; } return res; } int main() { #ifdef DEBUG freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif pis = pool; int n, opt, x; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d%d", &opt, &x); if(opt == 1) insert(x); else if(opt == 2) remove(root, x); else if(opt == 3) printf("%d\n", rank(root, x)); else if(opt == 4) printf("%d\n", kth(root, x)); else if(opt == 5) printf("%d\n", pre(root, x)); else printf("%d\n", suf(root, x)); } return 0; }
View Code
打删除标记的还没想好前驱后继怎么求TAT
相关文章推荐
- [Leetcode]Search for a Range
- 106.Oracle数据库SQL开发之 表——向表中添加注释
- PHP数组的遍历
- poj1011
- 安卓apk签名方法
- C语言常见问题分析(1)
- LIstView
- Hadoop2.6.0集群配置
- 动态规划-钢条切割(java)
- 105.Oracle数据库SQL开发之 表——重命名表
- Self-confidence
- 二叉树的遍历
- 《C++ primer》英文第五版阅读笔记(二十)——类型转换
- 给java的JFileChooser组件添加一个复选框
- Html自动播放音乐代码
- 104.Oracle数据库SQL开发之 表——修改表
- StringBuffer 清空的方法
- Nginx服务器
- hdu 1084 What Is Your Grade?(标记数据)
- 5.1.5 time对象