[您有新的未分配科技点]可,可,可持久化!?------可持久化平衡树普及版讲解
2017-08-03 13:46
288 查看
今天我们也继续精神满满的可持久化——这次我带来的是可持久化平衡树的讲解。
可持久化平衡树,顾名思义,和主席树一样支持历史版本的查询。
可持久化平衡树都可以用什么实现呢?朴素的二叉排序树,或者无旋Treap,或者替罪羊。其他的平衡树都不能实现可持久化
……好吧,我们直接把二叉排序树扔掉。下面我们来想一下。
splay是均摊的log复杂度,这是不清真的
可能某一次的复杂度很高,就导致复制了很多节点,因此是可以卡的……
但是换成重量平衡树就没事了。
我们想一想,重量平衡树:Treap和替罪羊
替罪羊要拍扁重建,这样之前可持久化的关系会被改变
有旋的Treap,因为要旋转,更新父子关系也很复杂
因此只剩下无旋Treap了2333
我们只需要在进行merge和split操作的时候进行可持久化,复制一下经过的节点即可。
在具体的代码实现上说,我们只多了一个函数:copy函数,用来复制(好像特意开一个函数不太值……233)
UPD 感谢rvalue dalao上面的a是传引用……我知识水平不够把这俩弄混了……
这样,我们只需要在merge和split函数中调用上面的cop函数来复制节点,就可以实现可持久化了。
更改后的split和merge代码如下
这样,我们就成功的实现了可持久化:)
给出一道例题 cogs2314 Persistable Editor http://cogs.pro/cogs/problem/problem.php?pid=2314
这道题就是在对序列维护实现一个可持久化的平衡树。直接利用无旋Treap实现即可。
下面给出我的代码:
平衡树是一种很强大的数据结构,而把它可持久化以后必然让他如虎添翼,能带来更多新的题型以及新的做法。希望你能从我的博客中学到什么:)
可持久化平衡树,顾名思义,和主席树一样支持历史版本的查询。
可持久化平衡树都可以用什么实现呢?朴素的二叉排序树,或者无旋Treap,或者替罪羊。其他的平衡树都不能实现可持久化
……好吧,我们直接把二叉排序树扔掉。下面我们来想一下。
splay是均摊的log复杂度,这是不清真的
可能某一次的复杂度很高,就导致复制了很多节点,因此是可以卡的……
但是换成重量平衡树就没事了。
我们想一想,重量平衡树:Treap和替罪羊
替罪羊要拍扁重建,这样之前可持久化的关系会被改变
有旋的Treap,因为要旋转,更新父子关系也很复杂
因此只剩下无旋Treap了2333
我们只需要在进行merge和split操作的时候进行可持久化,复制一下经过的节点即可。
在具体的代码实现上说,我们只多了一个函数:copy函数,用来复制(好像特意开一个函数不太值……233)
inline void cop(Treap *&a,Treap *b) { if(b==null)a=null; else a=newTreap(0),*a=*b; //这个函数的关键点有二:一是a要传引用,二是必须写*a=*b。 //*a=*b只把b存储的值赋给了a,而对a的操作不会影响b的值,即实现了可持久化 }
UPD 感谢rvalue dalao上面的a是传引用……我知识水平不够把这俩弄混了……
这样,我们只需要在merge和split函数中调用上面的cop函数来复制节点,就可以实现可持久化了。
更改后的split和merge代码如下
void split(Treap *rt,Treap *&a,Treap *&b,int k) { if(!k)cop(b,rt),a=null; else if(rt->size<=k)cop(a,rt),b=null; else if(rt->ch[0]->size>=k) cop(b,rt),split(rt->ch[0],a,b->ch[0],k),b->update(); else cop(a,rt),split(rt->ch[1],a->ch[1],b,k-rt->ch[0]->size-1),a->update(); } void merge(Treap *&rt,Treap *a,Treap *b) { if(a==null)cop(rt,b); else if(b==null)cop(rt,a); else if(a->key < b->key) cop(rt,a),merge(rt->ch[1],a->ch[1],b),rt->update(); else cop(rt,b),merge(rt->ch[0],a,b->ch[0]),rt->update(); }
这样,我们就成功的实现了可持久化:)
给出一道例题 cogs2314 Persistable Editor http://cogs.pro/cogs/problem/problem.php?pid=2314
这道题就是在对序列维护实现一个可持久化的平衡树。直接利用无旋Treap实现即可。
下面给出我的代码:
#include <cstdio> #include <cstring> #include <iostream> #include <ctime> #include <cstdlib> using namespace std; const int N=100005; int d,cnt;char s[250]; struct Treap { Treap *ch[2]; char val;int size,key; Treap(){val=size=0;key=rand();ch[0]=ch[1]=NULL;} inline void update(){size=ch[0]->size+ch[1]->size+1;} }*null=new Treap(),*root ; inline Treap* newTreap(char c) { Treap *o=new Treap();o->ch[0]=o->ch[1]=null; o->val=c;o->size=1;return o; } inline void cop(Treap *&a,Treap *b) { if(b==null)a=null; else a=newTreap(0),*a=*b; } void split(Treap *rt,Treap *&a,Treap *&b,int k) { if(!k)cop(b,rt),a=null; else if(rt->size<=k)cop(a,rt),b=null; else if(rt->ch[0]->size>=k) cop(b,rt),split(rt->ch[0],a,b->ch[0],k),b->update(); else cop(a,rt),split(rt->ch[1],a->ch[1],b,k-rt->ch[0]->size-1),a->update(); } void merge(Treap *&rt,Treap *a,Treap *b) { if(a==null)cop(rt,b); else if(b==null)cop(rt,a); else if(a->key < b->key) cop(rt,a),merge(rt->ch[1],a->ch[1],b),rt->update(); else cop(rt,b),merge(rt->ch[0],a,b->ch[0]),rt->update(); } void dfs(Treap *o) { if(o==null)return; dfs(o->ch[0]); printf("%c",o->val); if(o->val=='c')d++; dfs(o->ch[1]); } inline void print() { int mk,p,x; scanf("%d%d%d",&mk,&p,&x);mk-=d,p-=d,x-=d; Treap *a,*b,*c; split(root[mk],a,b,p-1),split(b,b,c,x); dfs(b);printf("\n"); merge(a,a,b),merge(root[mk],a,c); } inline Treap* build(char *t) { static Treap *stack[210],*x,*last; int p=0,m=strlen(t); for(int i=0;i<m;i++) { x=newTreap(s[i]);last=null; while(p&&stack[p]->key > x->key) {stack[p]->update();last=stack[p];stack[p--]=null;} if(p)stack[p]->ch[1]=x; x->ch[0]=last;stack[++p]=x; } while(p)stack[p--]->update(); return stack[1]; } inline void insert() { int p;scanf("%d%s",&p,s);p-=d; Treap *a,*b,*c=build(s); split(root[cnt],a,b,p); merge(a,a,c),merge(root[++cnt],a,b); } inline void del() { int p,x;scanf("%d%d",&p,&x);p-=d,x-=d; Treap *a,*b,*c; split(root[cnt],a,b,p-1),split(b,b,c,x); merge(root[++cnt],a,c); } int main() { int n,opt;scanf("%d",&n); null->ch[0]=null->ch[1]=null; for(int i=0;i<=n;i++)root[i]=null; while(n--) { scanf("%d",&opt); switch(opt) { case 1:insert();break; case 2:del();break; case 3:print();break; } } }
平衡树是一种很强大的数据结构,而把它可持久化以后必然让他如虎添翼,能带来更多新的题型以及新的做法。希望你能从我的博客中学到什么:)
相关文章推荐
- [您有新的未分配科技点]可,可,可持久化!?------0-1Trie和可持久化Trie普及版讲解
- [您有新的未分配科技点]可,可,可持久化!?------可持久化线段树普及版讲解
- BZOJ 3673/3674 可持久化并查集 by zky [rope可持久化平衡树]
- BZOJ3932 CQOI2015 任务查询系统-可持久化线段树-可持久化平衡树
- [您有新的未分配科技点]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)
- 使用Ceph集群作为Kubernetes的动态分配持久化存储
- BZOJ 3673: 可持久化并查集 by zky&&3674: 可持久化并查集加强版|主席树
- BZOJ 3224 Tyvj 1728 普通平衡树 | Splay 板子+SPlay详细讲解
- bzoj3674 可持久化并查集加强版 可持久化线段树
- [您有新的未分配科技点] 无旋treap:从单点到区间(例题 BZOJ1500&NOI2005 维护数列 )
- asp.net signalR 专题—— 第二篇 对PersistentConnection持久连接的快速讲解
- 内存对齐的初步讲解--linux和windows平台下内存分配的差异
- ActiveMQ中的消息的持久化和非持久化 以及 持久订阅者 和 非持久订阅者之间的区别与联系
- 【模板】可持久化平衡树(非旋Treap)
- BZOJ 3673: 可持久化并查集(可持久化并查集+启发式合并)
- Hibernate持久化对象的生命周期(三种状态:临时、持久、游离 )
- 云计算知识普及:太有才了:情色讲解“云计算”
- 【可持久化数据结构】主席树(可持久化线段树)
- JMS消息持久化,将ActiveMQ消息持久化到mySql数据库中
- 详细讲解从用户空间申请内存到内核如何为其分配内存的过程