约定:
int ch[maxd][3];//0左儿子,1右儿子
int val[maxd];//权值
int rnd[maxd];//随机权值
int sze[maxd];//以每个点为根树的大小
int T,rt,x,y,z;
分裂:
inline void update(int x)
{
sze[x]=1+sze[ch[x][0]]+sze[ch[x][1]];
}
//x为权值小于k的子树的根,y为剩下的子树的根
void split(int now,int k,int &x,int &y)//权值分裂
{
if(!now)
{
x=y=0;
return ;
}
else if(val[now]<=k)//它及它的左子树都小于等于k,递归向右找第二颗树
{
x=now;
split(ch[now][1],k,ch[now][1],y);
}
else
{
y=now;
split(ch[now][0],k,x,ch[now][0]);
}
update(now);//更新sze
}
//x为前k个的子树的根,y为剩下的子树的根
void split1(int now,int k,int &x,int &y)//单点
{
if(!now)
{
x=y=0;
}
else{
if(k<=sze[ch[now][0]])//左子树元素个数大于k个,将右子树全部放在第二颗树上,递归分裂左子树
{
y=now;
split1(ch[now][0],k,x,ch[now][0]);
}
else{
x=now;
split1(ch[now][1],k-sze[ch[now][0]]-1,ch[now][1],y);
}
}
update(now);
}
合并:
//我们假设第一棵树的权值小于第二棵树的权值,
//那么我们就比较它们的随机权值。
//如果rnd[l]<rnd[r],我们就保留它的左子树,
//另一棵树作为它的右子树;如果rnd[l]>=rnd[r],
//那我们可以保留第二棵树的右子树,另一颗树作为它的左子树。
int merge(int A,int B)
{
if(!A||!B)
{
return A+B;
}
if(rnd[A]<rnd[B])
{
ch[A][1]=merge(ch[A][1],B);
update(A);
return A;
}
else
{
ch[B][0]=merge(A,ch[B][0]);
update(B);
return B;
}
}
插入:
int new_node(int x)
{
sze[++T]=1;
val[T]=x;
rn