[Preface
]
莫得 Preface 。
[Description
]
【普通平衡树】的可持久化版本。
[Solution
]
我们知道 ( ext{fhq treap}) 是资瓷可持久化的。
重点就在于 ( ext{fhq treap}) 的核心操作 (split) 和 (merge) 上,这两个操作改变了 ( ext{fhq treap}) 的形态。
那也就是说我们在 (split) 和 (merge) 的时候,新建立节点,将原节点的信息赋给新节点,再进行操作,使得当前版本的 ( ext{fhq treap}) 不影响到之前版本的 ( ext{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) 的时候再多新建节点而保留那两棵要合并的树了。
剩下的操作只要复读复读复读就行了,或者说按有旋 ( ext{treap}) 一样的方式做。
时空复杂度 (Θ(n log n)) 。
[Code
]
#include<cstdio>
#include<cstdlib>
#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].size<rank)
return GetValByRank(t[p].rc,rank-t[t[p].lc].size-1);
}
int GetRankByVal(int p,int val)
{
if(!p)
return 0;
if(val<t[p].val)
return GetRankByVal(t[p].lc,val);
if(val==t[p].val)
return t[t[p].lc].size;
if(t[p].val<val)
return t[t[p].lc].size+1+GetRankByVal(t[p].rc,val);
}
int GetPre(int rt,int val)
{
int ans=-INF;
int p=rt;
while(p)
{
if(val==t[p].val)
{
if(t[p].lc>0)
{
p=t[p].lc;
while(t[p].rc>0)p=t[p].rc;
ans=t[p].val;
}
break;
}
if(t[p].val<val&&t[p].val>ans)ans=t[p].val;
p=val<t[p].val?t[p].lc:t[p].rc;
}
return ans;
}
int GetNext(int rt,int val)
{
int ans=INF;
int p=rt;
while(p)
{
if(val==t[p].val)
{
if(t[p].rc>0)
{
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<ans)ans=t[p].val;
p=val<t[p].val?t[p].lc:t[p].rc;
}
return ans;
}
int main()
{
insert(root[0],-INF),insert(root[0],INF);
m=read();
for(RI i=1;i<=m;i++)
{
int ver=read(),type=read(),val=read();
root[i]=root[ver];
switch(type)
{
case 1:{
insert(root[i],val);
break;
}
case 2:{
remove(root[i],val);
break;
}
case 3:{
printf("%d
",GetRankByVal(root[i],val));
break;
}
case 4:{
printf("%d
",GetValByRank(root[i],val+1));
break;
}
case 5:{
printf("%d
",GetPre(root[i],val));
break;
}
case 6:{
printf("%d
",GetNext(root[i],val));
break;
}
}
}
return 0;
}
[Thanks for watching
]