本人蒟蒻,在平衡树坑中深陷数年。为了早日逃离此天坑,特作此文。
什么是平衡树?度娘传送门
什么是treap?ACdreamers%%%
注:本篇所有代码都在片尾!!(醒目)
那么了解了这些,我们先列出一个list
NAME | 优势 | 劣势 |
---|---|---|
splay | LCT,序列之王 | 常数大,代码量稍大 |
RBT | 自适应深度平衡树,速度在同类BST中遥遥领先 | 代码量大 |
SBT | 代码简短,速度快,(退化版很好写) | 功能平平,(退化版会被人字梯数据卡掉) |
大体上来说,treap的敌人多为这三类。我们逆着证明treap是最强的。
就以常数来说,sbt与treap的常数皆为12左右,当然以数学证明的 (logn) sbt的常数肯定要比用期望 (logn) 的treap要稳很多,但是就我们平时直观所感觉的速度差,大多是因为rand()调用太耗时,所以解决此问题可以这样
inline int random(){
static int seed=703; //seed可以随便取
return seed=int(seed*48271LL%2147483647);
}
以数学的方法快速取得rand值 相关链接
这样一来比较不加读优,sbt为260ms+,treap为360ms+,速度已经很相近了。。。并且由于treap比sbt多一个rd数组存rand值,能有70%左右的速度已经非常可观了,但这不是重点。
Treap真正能够超越sbt的在于可以快速分裂与合并,这是sbt很难做到的,而且一旦去做,就必定会加入Father指针,这样会拖慢sbt旋转的速度。
详见代码 HERE
这可能是treap最大的敌人,速度足够碾压刚刚还得瑟的SBT(cqf的论文中虽然号称比AVL快[实际情况我还没有试过],但是不敢说比RBT快),STL中set,map这些常用类型的底层实现方式。
这就是让人恐惧并无法自拔(?)的RBT(红黑树)!!
那么这么强大的平衡树,为什么区区一介treap敢于挑战?
在与。。。还记得我对RBT的描述吗?深度平衡树
那么就用你的优势成为你失败的伏笔!!!
引出重量级
可以发现能够支撑起平衡树向字符串领域进军的,就是treap!!
复杂度在加入了一个类似于线段树的结构后并没有改变 (logn) 呢!暂且不论跳表的普及型以及删除时的恶心程度,一般非确定型跳表的空间复杂的是高于树形结构的BST的,其次跳表根本不是主流吧!!然后替罪羊树比起treap来说要难写一点(毕竟要重建笛卡尔树。。)
综上,treap可以完成许多深度平衡树(AVL、RBT)(SBT算什么?)无法做到的效果。
首先分裂与合并已经在讨论sbt时解决了,再者splay的常数又是在平衡数中排得上名号的(大根堆),单旋spaly直接被链式数据卡死,所以splay只有在序列与LCT上称王称霸。LCT有关
但真的是这样吗?
谈谈Treap与LCT,既然都能不旋转来分裂合并了,那么LCT自然是手到擒来。LCT例子
CDQZ本部的几个大神就是LCT只打treap。
所以splay能得瑟的就是序列之王这个名号了!
光速打脸 NOI2005 维护数列
呵呵,虽然分裂合并式的Treap,速度慢,但是代码很好写,毕竟靠随机值无脑合并分裂啊。
的确,treap在速度上输给了sbt、rbt(远远地),代码量上也仅仅与sbt持平(基础部分不到40行),分裂合并的常数值也比splay大。。
(观众:好像一无是处耶?)
但是treap反向证明了它自己可以做到那么多不同平衡树自己独具特点的功能,就好比金庸集各家之大成,虽未超越,但单单地将其聚合起来也足以称王了。
从重量平衡引申出的后缀平衡树,非旋转式引出分裂与合并,treap很弱,因为它不完整(从定义上就不完整),但也正是如此他对于OIer来说不是如RBT般的神,splay般的功能强大,sbt般的简洁飞速,所以它需要成长,对于没一点常数的争取,对于自身结构的改变,以及。。。。。本文最后的彩蛋!!
这是多少OIer在可持久化treap发明前学平衡树的心结,那么强大的平衡树为什么没有能简单可持久化的方式呢?直到可持久化treap横空出世,震惊全球(夸张。),多少代OIer的愿望通过treap残缺的美在此得以实现。
bzoj3224 普通平衡树
#include
#include
#include
using namespace std;
struct data{
int l,r,v,size,rnd,w;
}tr[100005];
int n,size,root,ans;
inline int randad(){
static int seed=703; //seed可以随便取
return seed=int(seed*48271LL%2147483647);
}
void update(int k)//更新结点信息
{
tr[k].size=tr[tr[k].l].size+tr[tr[k].r].size+tr[k].w;
}
void rturn(int &k)
{
int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k;
tr[t].size=tr[k].size;update(k);k=t;
}
void lturn(int &k)
{
int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k;
tr[t].size=tr[k].size;update(k);k=t;
}
void insert(int &k,int x)
{
if(k==0)
{
size++;k=size;
tr[k].size=tr[k].w=1;tr[k].v=x;tr[k].rnd=randad();
return;
}
tr[k].size++;
if(tr[k].v==x)tr[k].w++;
else if(x>tr[k].v)
{
insert(tr[k].r,x);
if(tr[tr[k].r].rndelse
{
insert(tr[k].l,x);
if(tr[tr[k].l].rnd void del(int &k,int x)
{
if(k==0)return;
if(tr[k].v==x)
{
if(tr[k].w>1)
{
tr[k].w--;tr[k].size--;return;
}
if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r;
else if(tr[tr[k].l].rnd else lturn(k),del(k,x);
}
else if(x>tr[k].v)
tr[k].size--,del(tr[k].r,x);
else tr[k].size--,del(tr[k].l,x);
}
int query_rank(int k,int x)
{
if(k==0)return 0;
if(tr[k].v==x)return tr[tr[k].l].size+1;
else if(x>tr[k].v)
return tr[tr[k].l].size+tr[k].w+query_rank(tr[k].r,x);
else return query_rank(tr[k].l,x);
}
int query_num(int k,int x)
{
if(k==0)return 0;
if(x<=tr[tr[k].l].size)
return query_num(tr[k].l,x);
else if(x>tr[tr[k].l].size+tr[k].w)
return query_num(tr[k].r,x-tr[tr[k].l].size-tr[k].w);
else return tr[k].v;
}
void query_pro(int k,int x)
{
if(k==0)return;
if(tr[k].velse query_pro(tr[k].l,x);
}
void query_sub(int k,int x)
{
if(k==0)return;
if(tr[k].v>x)
{
ans=k;query_sub(tr[k].l,x);
}
else query_sub(tr[k].r,x);
}
int main()
{
scanf("%d",&n);
int opt,x;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&opt,&x);
switch(opt)
{
case 1:insert(root,x);break;
case 2:del(root,x);break;
case 3:printf("%d\n",query_rank(root,x));break;
case 4:printf("%d\n",query_num(root,x));break;
case 5:ans=0;query_pro(root,x);printf("%d\n",tr[ans].v);break;
case 6:ans=0;query_sub(root,x);printf("%d\n",tr[ans].v);break;
}
}
return 0;
}
序列treap
BZOJ1500 维护数列
#define INF 2000000000
#define N 500010
struct Node;
Node *null,*root;
struct Node
{
int w,sz,val,sum,ls,rs,ss,lzy1,lzy2;
Node *lft,*rht;
void split(int,Node*&,Node*&);
void same(int v)
{
if(this==null) return;
lzy2=val=v;
sum=v*sz;
ls=rs=ss=max(sum,v);
}
void rev()
{
if(this==null) return;
lzy1^=1;
swap(lft,rht);
swap(ls,rs);
}
Node *pushup()
{
sz=lft->sz+1+rht->sz;
sum=lft->sum+val+rht->sum;
ls=max(lft->ls,lft->sum+val+max(0,rht->ls));
rs=max(rht->rs,rht->sum+val+max(0,lft->rs));
ss=max(0,lft->rs)+val+max(0,rht->ls);
ss=max(ss,max(lft->ss,rht->ss));
return this;
}
Node *pushdown()
{
if(lzy1)
{
lft->rev();
rht->rev();
lzy1=0;
}
if(lzy2!=-INF)
{
lft->same(lzy2);
rht->same(lzy2);
lzy2=-INF;
}
return this;
}
};
Node *merge(Node *p,Node *q)
{
if(p==null) return q;
if(q==null) return p;
if(p->ww)
{
p->pushdown();
p->rht=merge(p->rht,q);
return p->pushup();
}
q->pushdown();
q->lft=merge(p,q->lft);
return q->pushup();
}
void Node::split(int need,Node *&p,Node *&q)
{
if(this==null)
{
p=q=null;
return;
}
pushdown();
if(lft->sz>=need)
{
lft->split(need,p,q);
lft=null;
pushup();
q=merge(q,this);
return;
}
rht->split(need-(lft->sz+1),p,q);
rht=null;
pushup();
p=merge(this,p);
return;
}
Node data[N],*pool[N];
int top,cnt;
Node* newnode(int c)
{
Node *x;
if(top) x=pool[top--];
else x=&data[cnt++];
x->lft=x->rht=null;
x->sz=1; x->lzy1=0; x->lzy2=-INF;
x->val=x->sum=x->ls=x->rs=x->ss=c;
x->w=rands();
return x;
}
void init()
{
cnt=1; top=0;
null=&data[0];
null->sz=null->sum=0;
null->val=null->ls=null->rs=null->ss=-INF;
null->lzy1=0;
null->lzy2=-INF;
null->lft=null->rht=null;
}
//---------------------------------------------------------
void erase(Node *rt)
{
if(rt==null) return;
erase(rt->lft);
erase(rt->rht);
pool[++top]=rt;
}
int n,m;
char ord[20];
int a,b,c;
int main ()
{
init();
root=null;
n=fastget();
m=fastget();
for(int i=0;iwhile (m--)
{
scanf("%s",ord);
Node *p,*q,*r,*s;
if(ord[0]=='I')
{
a=fastget();
n=fastget();
root->split(a,p,q);
for(int i=0;ielse if(ord[0]=='D')
{
a=fastget();
b=fastget();
b=a+b-1;
root->split(a-1,p,q);
q->split(b-a+1,r,s);
erase(r);
root=merge(p,s);
}else if(ord[0]=='M' && ord[2]=='K')
{
a=fastget();
b=fastget();
c=fastget();
b=b+a-1;
root->split(a-1,p,q);
q->split(b-a+1,r,s);
r->same(c);
root=merge(p,merge(r,s));
}else if(ord[0]=='R')
{
a=fastget();
b=fastget();
b=b+a-1;
root->split(a-1,p,q);
q->split(b-a+1,r,s);
r->rev();
root=merge(p,merge(r,s));
}else if(ord[0]=='G')
{
a=fastget();
b=fastget();
b=a+b-1;
root->split(a-1,p,q);
q->split(b-a+1,r,s);
fastput(r->sum);
root=merge(p,merge(r,s));
}
else if(ord[0]=='M') fastput(root->ss);
}
return 0;
}
重量平衡树&后缀平衡树
BZOJ 3682: Phorni
#include
#include
#include
#include
using namespace std;
template<class T>inline void read(T &res){
static char ch;T flag=1;
while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;res=ch-48;
while((ch=getchar())>='0'&&ch<='9')res=(res<<1)+(res<<3)+ch-48;res*=flag;
}
#define N 500010
#define LL long long
int n,m,len,type,lastans,x,y;
int ch[N][2],rd[N],cl[N],cnt,root;
LL rk[N];
inline int randlmy(){
static int seed=173;
return seed=int(seed*48271LL%2147483647);
}
int cmp(int x,int y){
return cl[x]1]1]);
}
void rebuild(int &rt,LL l,LL r){
if(!rt)return;
rk[rt]=l+r;
LL mid=(l+r)>>1;
rebuild(ch[rt][0],l,mid);
rebuild(ch[rt][1],mid,r);
}
void rotate(int &p,int d,LL l,LL r){
int q=ch[p][d^1];
ch[p][d^1]=ch[q][d];
ch[q][d]=p;
p=q;
rebuild(p,l,r);
}
void insert(int &rt,LL l,LL r){
LL mid=(r+l)>>1;
if(!rt){rt=cnt;rk[rt]=l+r;return;}
if(cmp(cnt,rt)){insert(ch[rt][0],l,mid);if(rd[ch[rt][0]]>rd[rt])rotate(rt,1,l,r);}
else{insert(ch[rt][1],mid,r);if(rd[ch[rt][1]]>rd[rt])rotate(rt,0,l,r);}
}
void insert(int v){
cl[++cnt]=v;
rd[cnt]=randlmy()*randlmy();
insert(root,1,1LL<<61);
}
#define R(rt) rt<<1|1
#define L(rt) rt<<1
int minn[N<<2],p[N];
void build(int rt,int l,int r){
if(l==r)read(p[l]),minn[rt]=l;
else{
int mid=(l+r)>>1,lc=L(rt),rc=R(rt);
build(lc,l,mid);
build(rc,mid+1,r);
minn[rt]=rk[p[minn[lc]]]<=rk[p[minn[rc]]]?minn[lc]:minn[rc];
}
}
void updata(int rt,int l,int r,int id){
if(l==r)return;
int mid=(l+r)>>1,lc=L(rt),rc=R(rt);
if(id<=mid)updata(lc,l,mid,id);
else updata(rc,mid+1,r,id);
minn[rt]=rk[p[minn[lc]]]<=rk[p[minn[rc]]]?minn[lc]:minn[rc];
}
int query(int rt,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return minn[rt];
int mid=(l+r)>>1,lc=L(rt),rc=R(rt);
if(qr<=mid)return query(lc,l,mid,ql,qr);
if(ql>mid)return query(rc,mid+1,r,ql,qr);
int vl=query(lc,l,mid,ql,qr),vr=query(rc,mid+1,r,ql,qr);
return rk[p[vl]]<=rk[p[vr]]?vl:vr;
}
char s[N],cmd[5];
int main(){
read(n),read(m),read(len),read(type);
scanf("%s",s);
for(register int i=1;i<=len;i++)
insert(s[len-i]-'a');
build(1,1,n);
while(m--){
scanf("%s",cmd);
if(!type)lastans=0;
if(cmd[0]=='I')
read(x),insert(x^lastans),++len;
else if(cmd[0]=='C')
read(x),read(p[x]),updata(1,1,n,x);
else
read(x),read(y),
printf("%d\n",lastans=query(1,1,n,x,y));
}
return 0;
}
可持久化Treap
POJ 3580 SuperMemo
#include
#include
#include
#include
#include
#include
using namespace std;
struct treap_node{
treap_node *left,*right;
int val,fix,size,wgt,minn,adel,rdel;
treap_node(int val): val(val) {left=right=NULL; fix=rand(); wgt=size=1; minn=val; rdel=adel=0; }
int lsize()
{
if (left)
return left->size;
else
return 0;
}
int rsize()
{
if (right)
return right->size;
else
return 0;
}
void updata()
{
minn=val;
if (left)
minn=min(minn,left->minn+left->adel);
if (right)
minn=min(minn,right->minn+right->adel);
}
void pushdown()
{
treap_node *temp;
if (adel)
{
minn+=adel;
val+=adel;
if (left)
left->adel+=adel;
if (right)
right->adel+=adel;
adel=0;
}
if (rdel%2)
{
if (left==NULL||right==NULL)
{
if (left==NULL)
{
left=right;
right=NULL;
}
else
{
right=left;
left=NULL;
}
}
else
{
temp=left;
left=right;
right=temp;
}
if (left)
left->rdel+=rdel;
if (right)
right->rdel+=rdel;
rdel=0;
}
updata();
}
void Maintain()
{
size=wgt;
size+=lsize()+rsize();
}
};
int n,m;
treap_node *root;
typedef pair droot;
treap_node *merge(treap_node *a,treap_node *b)
{
if (!a) return b;
if (!b) return a;
a->pushdown(); b->pushdown();
a->updata(); b->updata();
if (a->fixfix)
{
a->right=merge(a->right,b);
a->updata();
a->Maintain();
return a;
}
else
{
b->left=merge(a,b->left);
b->updata();
b->Maintain();
return b;
}
}
droot split(treap_node *a,int k)
{
if (!a) return droot(NULL,NULL);
droot y;
a->pushdown(); a->updata();
if (a->lsize()>=k)
{
y=split(a->left,k);
a->left=y.second;
a->updata();
a->Maintain();
y.second=a;
}
else
{
y=split(a->right,k-a->lsize()-1);
a->right=y.first;
a->updata();
a->Maintain();
y.first=a;
}
return y;
}
void insert(int k,int value)
{
treap_node *temp;
droot y=split(root,k);
temp=new treap_node(value);
root=merge(merge(y.first,temp),y.second);
}
void del(int k)
{
droot x,y;
x=split(root,k-1);
y=split(x.second,1);
root=merge(x.first,y.second);
}
int main()
{
char s[20];
droot ai,bi,ci;
treap_node *temp;
int i,x,y,a,L,t;
scanf("%d",&n);
for (i=1;i<=n;++i)
{
scanf("%d",&x);
insert(i,x);
}
scanf("%d",&m);
for (i=1;i<=m;++i)
{
scanf("%s",&s);
if (s[0]=='A')
{
scanf("%d%d%d",&x,&y,&a);
ai=split(root,x-1);
bi=split(ai.second,y-x+1);
bi.first->adel+=a;
ai.second=merge(bi.first,bi.second);
root=merge(ai.first,ai.second);
}
if (s[0]=='I')
{
scanf("%d%d",&x,&a);
insert(x,a);
}
if (s[0]=='D')
{
scanf("%d",&x);
del(x);
}
if (s[0]=='R')
{
if (s[3]=='E')
{
scanf("%d%d",&x,&y);
ai=split(root,x-1);
bi=split(ai.second,y-x+1);
bi.first->rdel++;
ai.second=merge(bi.first,bi.second);
root=merge(ai.first,ai.second);
}
if (s[3]=='O')
{
scanf("%d%d%d",&x,&y,&a);
L=y-x+1;
a=(a%L+L)%L;
ai=split(root,x-1);
bi=split(ai.second,L);
ci=split(bi.first,L-a);
bi.first=merge(ci.second,ci.first);
ai.second=merge(bi.first,bi.second);
root=merge(ai.first,ai.second);
}
}
if (s[0]=='M')
{
scanf("%d%d",&x,&y);
ai=split(root,x-1);
bi=split(ai.second,y-x+1);
t=bi.first->minn;
ai.second=merge(bi.first,bi.second);
root=merge(ai.first,ai.second);
printf("%d\n",t);
}
}
}
补一句,多年的超文本编辑器问题也解决了。。。。
TREAP最强,TREAP赛高!!
你可能感兴趣的:(可持久化,数据结构与算法)