【模板】可持久化平衡树

传送门

Description

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作(对于各个以往的历史版本):

  1. 插入x数
  2. 删除x数(若有多个相同的数,因只删除一个,如果没有请忽略该操作)
  3. 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
  4. 查询排名为x的数
  5. 求x的前驱(前驱定义为小于x,且最大的数,如不存在输出-2147483647)
  6. 求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!

posted @ 2018-12-28 13:05  PaperCloud  阅读(162)  评论(0编辑  收藏  举报