\[ Preface \]
莫得 Preface 。
\[ Description \]
【普通平衡树】的可持久化版本。
\[ Solution \]
我们知道 \(\text{fhq treap}\) 是资瓷可持久化的。
重点就在于 \(\text{fhq treap}\) 的核心操作 \(split\) 和 \(merge\) 上,这两个操作改变了 \(\text{fhq treap}\) 的形态。
那也就是说我们在 \(split\) 和 \(merge\) 的时候,新建立节点,将原节点的信息赋给新节点,再进行操作,使得当前版本的 \(\text{fhq treap}\) 不影响到之前版本的 \(\text{fhq treap}\) ,就达到了可持久化的目的。
split
void split_v(int p,int val,int &x,int &y)
{
if(!p)
x=y=0;
else
{
if(t[p].val<=val)
{
x=++tot,t[x]=t[p];
split_v(t[x].rc,val,t[x].rc,y),upd(x);
}
else
{
y=++tot,t[y]=t[p];
split_v(t[y].lc,val,x,t[y].lc),upd(y);
}
}
}
merge
int merge(int p,int q)
{
if(!p||!q)
return p^q;
else
{
int now=++tot;
if(t[p].dat>t[q].dat)
t[now]=t[p],t[now].rc=merge(t[now].rc,q);
else
t[now]=t[q],t[now].lc=merge(p,t[now].lc);
upd(now);
return now;
}
}
但实际上 \(insert\) 和 \(remove\) 的时候,我们在 \(split\) 的过程中已经完成了新建节点这一步,就没必要在 \(merge\) 的时候再多新建节点而保留那两棵要合并的树了。
剩下的操作只要复读复读复读就行了,或者说按有旋 \(\text{treap}\) 一样的方式做。
时空复杂度 \(Θ(n \log n)\) 。
\[ Code \]
#include
#include
#define RI register int
using namespace std;
inline int read()
{
int x=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
return x*f;
}
const int N=500100,MLOGN=30001000;
const int INF=2147483647;
int m;
int tot,root[N];
struct treap{
int lc,rc;
int val,dat;
int size;
}t[MLOGN];
int New(int val)
{
tot++;
t[tot].lc=t[tot].rc=0;
t[tot].val=val,t[tot].dat=rand();
t[tot].size=1;
return tot;
}
void upd(int p)
{
t[p].size=t[t[p].lc].size+t[t[p].rc].size+1;
}
void split_v(int p,int val,int &x,int &y)
{
if(!p)
x=y=0;
else
{
if(t[p].val<=val)
{
x=++tot,t[x]=t[p];
split_v(t[x].rc,val,t[x].rc,y),upd(x);
}
else
{
y=++tot,t[y]=t[p];
split_v(t[y].lc,val,x,t[y].lc),upd(y);
}
}
}
int merge(int p,int q)
{
if(!p||!q)
return p^q;
if(t[p].dat>t[q].dat)
{
t[p].rc=merge(t[p].rc,q),upd(p);
return p;
}
else
{
t[q].lc=merge(p,t[q].lc),upd(q);
return q;
}
}
int x,y,z;
void insert(int &rt,int val)
{
split_v(rt,val-1,x,y);
rt=New(val);
rt=merge(x,rt);
rt=merge(rt,y);
}
void remove(int &rt,int val)
{
split_v(rt,val-1,x,y);
split_v(y,val,y,z);
y=merge(t[y].lc,t[y].rc);
rt=merge(x,y);
rt=merge(rt,z);
}
int GetValByRank(int p,int rank)
{
if(!p)
return INF;
if(rank<=t[t[p].lc].size)
return GetValByRank(t[p].lc,rank);
if(rank==t[t[p].lc].size+1)
return t[p].val;
if(t[t[p].lc].size0)
{
p=t[p].lc;
while(t[p].rc>0)p=t[p].rc;
ans=t[p].val;
}
break;
}
if(t[p].valans)ans=t[p].val;
p=val0)
{
p=t[p].rc;
while(t[p].lc>0)p=t[p].lc;
ans=t[p].val;
}
break;
}
if(t[p].val>val&&t[p].val
\[ Thanks \ for \ watching \]