【模板】可持久化平衡树
传送门
Description
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作(对于各个以往的历史版本):
- 插入x数
- 删除x数(若有多个相同的数,因只删除一个,如果没有请忽略该操作)
- 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
- 查询排名为x的数
- 求x的前驱(前驱定义为小于x,且最大的数,如不存在输出-2147483647)
- 求x的后继(后继定义为大于x,且最小的数,如不存在输出2147483647)
和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本。(操作3, 4, 5, 6即保持原版本无变化)
每个版本的编号即为操作的序号(版本0即为初始状态,空树)
Solution
当然是可持久化fhq啦
Wa了好久,原来是没有注意到删数时,如果没有这个操作,要忽略它
动态加点就和可持久化线段树一样,反正是很好打
Code
#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
#define MN 500005*50
int sz,rt[MN];
int val[MN],pri[MN],ls[MN],rs[MN],siz[MN];
unsigned int myrand()
{
static unsigned int x=23333;
return x^=x<<13,x^=x>>17,x^=x<<5;
}
inline void combine(int x){siz[x]=1+siz[ls[x]]+siz[rs[x]];}
int NewNode(int x)
{
++sz;
val[sz]=val[x];pri[sz]=pri[x];ls[sz]=ls[x];
rs[sz]=rs[x];siz[sz]=siz[x];
return sz;
}
int Merge(int rt1,int rt2)
{
if(!rt1||!rt2) return rt2|rt1;
if(pri[rt1]<pri[rt2])
{
register int p=NewNode(rt1);
rs[p]=Merge(rs[rt1],rt2);
combine(p);return p;
}
else
{
register int p=NewNode(rt2);
ls[p]=Merge(rt1,ls[rt2]);
combine(p);return p;
}
}
void Split(int x,int k,int&rt1,int&rt2)
{
if(!x) return (void)(rt1=rt2=0);
if(k<=siz[ls[x]])
{
rt2=NewNode(x);
Split(ls[x],k,rt1,ls[rt2]);
combine(rt2);
}
else
{
rt1=NewNode(x);
Split(rs[x],k-siz[ls[x]]-1,rs[rt1],rt2);
combine(rt1);
}
}
int Rank(int x,int v)
{
if(!x) return 0;
if(v<val[x]) return Rank(ls[x],v);
else return siz[ls[x]]+Rank(rs[x],v)+1;
}
int Kth(int &root,int k)
{
register int rt1,rt2,rt3,c;
Split(root,k,rt1,rt2);Split(rt1,k-1,rt3,c);
root=Merge(rt3,Merge(c,rt2));
return val[c];
}
void Insert(int &root,int v)
{
val[++sz]=v;pri[sz]=myrand(),siz[sz]=1;
register int rk=Rank(root,v),rt1,rt2,c=sz;
Split(root,rk,rt1,rt2);
root=Merge(Merge(rt1,c),rt2);
}
void Delete(int &root,int v)
{
register int rk=Rank(root,v),rt1,rt2,rt3,c;
Split(root,rk,rt1,rt2);Split(rt1,rk-1,rt3,c);
if(val[c]!=v){root=Merge(Merge(rt3,c),rt2);return;}
root=Merge(rt3,rt2);
}
int main(){
// freopen("testdata.in","r",stdin);
// freopen("testdata.out","w",stdout);
register int m=read(),v,opt,x,i;
Insert(rt[0],2147483647);Insert(rt[0],-2147483647);
for(i=1;i<=m;++i)
{
v=read(),opt=read(),x=read();rt[i]=rt[v];
switch(opt)
{
case 1: Insert(rt[i],x);break;
case 2: Delete(rt[i],x);break;
case 3: printf("%d\n",Rank(rt[i],x-1));break;
case 4: printf("%d\n",Kth(rt[i],x+1));break;
case 5: printf("%d\n",Kth(rt[i],Rank(rt[i],x-1)));break;
case 6: printf("%d\n",Kth(rt[i],Rank(rt[i],x)+1));break;
}
}
return 0;
}
Blog来自PaperCloud,未经允许,请勿转载,TKS!
致虚极,守静笃,万物并作,吾以观其复