从普通平衡树到可持久化平衡树

从普通平衡树到可持久化平衡树

这篇只是一个模板,没有写讲解,写得不好,别看!

  1. 普通平衡树

    1. 操作分别为

      1. 插入 x数
      2. 删除 x 数(若有多个相同的数,因只删除一个)
      3. 查询 x 数的排名(排名定义为比当前数小的数的个数 +1 )
      4. 查询排名为 x 的数
      5. 求 x 的前驱(前驱定义为小于 x,且最大的数)
      6. 求 x的后继(后继定义为大于 x,且最小的数)
    2. Splay版本(为了防止特殊数据,添加了随机换根操作)

      1. #include<iostream>
        #include<stdio.h>
        #include<string.h>
        #include<algorithm>
        #include<set>
        #define maxn 100005
        #define lson son[now][0]
        #define rson son[now][1]
        using namespace std;
        set<int> s;
        int n,root,tot;
        int son[maxn][2],fa[maxn],val[maxn],siz[maxn];
        void pushup(int now)
        {
        	siz[now]=siz[lson]+siz[rson]+1;
        }
        void rotate(int x,int &k)
        {
        	int y=fa[x],z=fa[y],l,r;
        	l=son[y][1]==x;r=l^1;
        	if(y==k) k=x;
        	else {if(son[z][0]==y) son[z][0]=x;else son[z][1]=x;}
        	fa[x]=z;fa[y]=x;fa[son[x][r]]=y;
        	son[y][l]=son[x][r];son[x][r]=y;
        	pushup(y);pushup(x);
        }
        void splay(int x,int &k)
        {
        	while(x!=k)
        	{
        		int y=fa[x],z=fa[y];
        		//cout<<"fuck "<<x<<' '<<y<<" "<<k<<endl;
        		if(y!=k)
        		{
        			if((son[y][0]==x)^(son[z][0]==y)) rotate(x,k);
        			else rotate(y,k);
        		}
        		rotate(x,k);
        	}
        }
        int cnt;
        void insert(int &now,int v,int last)
        {
        	//cnt++;
        	if(!now)
        	{
        		now=++tot;
        		s.insert(tot);
        		val[tot]=v;
        		fa[now]=last;
        		splay(tot,root);
        		int temp=rand()%tot+1;
        		if(s.find(temp)!=s.end())
        			splay(temp,root);
        		cnt=0;
        		return;
        	}
        	if(v<=val[now]) insert(lson,v,now);
        	else insert(rson,v,now);
        }
        void del(int v)
        {
        	int pos=root;
        	while(val[pos]!=v) pos=son[pos][val[pos]<v]; 	splay(pos,root);
        	
        	s.erase(pos);
        	
        	int now=son[pos][1],flag;
        	if(!now)
        	{
        		flag=1;
        		now=son[pos][0];
        		if(!now)
        		{
        			fa[pos]=0;
        			val[pos]=0;
        			root=0;
        			return;
        		}
        	}
        	else 
        		flag=0;
        	while(son[now][flag]) now=son[now][flag];
        	
        	
        	int t=root;splay(now,root);
        	son[now][flag]=son[t][flag];fa[son[t][flag]]=now;fa[now]=0;
        	pushup(now);
        }
        int getrank(int v)
        {
        	cnt=0;
        	int now=root,ans=0;
        	while(now)
        	{
        		cnt++;
        		if(v>val[now]) {ans+=siz[lson]+1;now=rson;}
        		else now=lson;
        	}
        	//cerr<<"its "<<cnt<<endl;
        	return ans+1;
        }
        int find(int v)
        {
        	int now=root;
        	while(now)
        	{
        		if(siz[lson]+1==v) return val[now];
        		else if(siz[lson]+1>v) now=lson;
        		else v-=(siz[lson]+1),now=rson;
        	}
        	return val[now];
        }
        int suf(int v)
        {
        	int now=root,ans;
        	while(now)
        	{
        		if(val[now]<v){ans=val[now];now=rson;}
        		else now=lson;
        	}
        	return ans;
        }
        int nex(int v)
        {
        	int now=root,ans;
        	while(now)
        	{
        		if(val[now]<=v) now=rson;
        		else {ans=val[now];now=lson;}
        	}
        	return ans;
        }
        int main()
        {
        	scanf("%d",&n);
        	while(n--)
        	{
        		int op,x;
        		scanf("%d%d",&op,&x);
        		if(op==1) insert(root,x,0);
        		if(op==2) del(x);
        		if(op==3) printf("%d\n",getrank(x));
        		if(op==4) printf("%d\n",find(x));
        		if(op==5) printf("%d\n",suf(x));
        		if(op==6) printf("%d\n",nex(x));
        	}
        }
        
    3. Treap版本(好写)

      1. #include<stdio.h>
        #include<string.h>
        #include<stdlib.h>
        #define maxn 100005
        #define lson son[now][0]
        #define rson son[now][1]
        #define min(a,b) ((a)<(b) ? (a):(b))
        #define max(a,b) ((a)>(b) ? (a):(b))
        const int inf=2e9+5;
        typedef struct nod
        {
        	int first,second;
        } nod;
        int root,tot,sz[maxn];
        int son[maxn][2],val[maxn],k[maxn];
        void pushup(int now)
        {
            sz[now]=sz[lson]+sz[rson]+1;
        }
        int merge(int x,int y)
        {
            if(!x || !y) return x+y;
            if(k[x]<k[y]) return son[x][1]=merge(son[x][1],y),pushup(x),x;
            else return son[y][0]=merge(x,son[y][0]),pushup(y),y;
        }
        nod split(int now,int v)
        {
            if(!now)
            {
            	nod temp;
            	temp.first=0;
            	temp.second=0;
            	return temp;
        	}
            nod y;
            if(sz[lson]>=v)
            {
                y=split(lson,v);
                lson=y.second;
                pushup(now);
                y.second=now;
            }
            else
            {
                y=split(rson,v-sz[lson]-1);
                rson=y.first;
                pushup(now);
                y.first=now;
            }
            return y;
        }
        int find(int v)
        {
            nod x=split(root,v-1),y=split(x.second,1);
            int ans=y.first;
            root=merge(merge(x.first,ans),y.second);
            return val[ans];
        }
        int rk(int now,int v)
        {
            int minn=inf,maxx=0;
            while(now)
            {
                if(val[now]==v) minn=min(minn,maxx+sz[lson]+1);
                if(v>val[now]) maxx+=sz[lson]+1,now=rson;
                else now=lson;
            }
            return minn==inf ? maxx : minn;
        }
        void insert(int v)
        {
            int pos=rk(root,v);
            nod x=split(root,pos);
            sz[++tot]=1; val[tot]=v; k[tot]=rand();
            root=merge(merge(x.first,tot),x.second);
        }
        void del(int v)
        {
            int pos=rk(root,v);
            nod x=split(root,pos-1),y=split(x.second,1);
            root=merge(x.first,y.second);
        }
        int suc(int v)
        {
            int now=root,ans=inf;
            while(now)
            {
                if(val[now]>v)
                {
                    ans=min(ans,val[now]);
                    now=lson;
                }
                else
                    now=rson;
            }
            return ans;
        }
        int pre(int v)
        {
            int now=root,ans=-inf;
            while(now)
            {
                if(val[now]<v)
                {
                    ans=max(ans,val[now]);
                    now=rson;
                }
                else
                    now=lson;
            }
            return ans;
        }
        int main()
        {
            int _;
            scanf("%d",&_);
            while(_--)
            {
                int op,x;
                scanf("%d%d",&op,&x);
                if(op==1)
                    insert(x);
                if(op==2)
                    del(x);
                if(op==3)
                    printf("%d\n",rk(root,x));
                if(op==4)
                    printf("%d\n",find(x));
                if(op==5)
                    printf("%d\n",pre(x));
                if(op==6)
                    printf("%d\n",suc(x));
            }
            return 0;
        }
        
  2. 文艺平衡树

    1. 集成区间赋值和翻转的Splay

      1. #include<iostream>
        #include<stdio.h>
        #include<string.h>
        #include<algorithm>
        #include<queue> 
        #define inf 1000000000
        #define maxn 1000005
        using namespace std;
        int n,m,root,cnt;
        queue<int>q;
        bool tag[maxn],rev[maxn];
        int fa[maxn],id[maxn],a[maxn],son[maxn][2];
        int sum[maxn],siz[maxn],v[maxn],maxx[maxn],lx[maxn],rx[maxn];
        void pushup(int now)
        {
        	int lson=son[now][0],rson=son[now][1];
        	sum[now]=sum[lson]+sum[rson]+v[now];
        	siz[now]=siz[lson]+siz[rson]+1;
        	maxx[now]=max(maxx[lson],maxx[rson]);
        	maxx[now]=max(maxx[now],lx[rson]+v[now]+rx[lson]);
        	lx[now]=max(lx[lson],sum[lson]+v[now]+lx[rson]);
        	rx[now]=max(rx[rson],sum[rson]+v[now]+rx[lson]);
        }
        void pushdown(int now)
        {
        	int lson=son[now][0],rson=son[now][1];
        	if(tag[now])
        	{
        		tag[now]=rev[now]=0;
        		if(lson) tag[lson]=1,v[lson]=v[now],sum[lson]=v[now]*siz[lson];
        		if(rson) tag[rson]=1,v[rson]=v[now],sum[rson]=v[now]*siz[rson];
        		if(v[now]>=0)
        		{
        			if(lson) lx[lson]=rx[lson]=maxx[lson]=sum[lson];
        			if(rson) lx[rson]=rx[rson]=maxx[rson]=sum[rson];
        		}
        		else
        		{
        			if(lson) lx[lson]=rx[lson]=0,maxx[lson]=v[now];
        			if(rson) lx[rson]=rx[rson]=0,maxx[rson]=v[now];
        		}
        	}
        	if(rev[now])
        	{
        		rev[now]^=1;rev[lson]^=1;rev[rson]^=1;
        		swap(lx[lson],rx[lson]);swap(lx[rson],rx[rson]);
        		swap(son[lson][0],son[lson][1]);swap(son[rson][0],son[rson][1]);
        	}
        }
        void rotate(int x,int &k)
        {
        	int y=fa[x],z=fa[y],l,r;
        	l=(son[y][1]==x);r=l^1;
        	if(y==k) k=x;
        	else son[z][son[z][1]==y]=x;
        	fa[son[x][r]]=y;fa[y]=x;fa[x]=z;
        	son[y][l]=son[x][r];son[x][r]=y;
        	pushup(y);pushup(x);//顺序千万不能错 
        }
        void splay(int x,int &k)
        {
        	while(x!=k)
        	{
        		int y=fa[x],z=fa[y];
        		if(y!=k)
        		{
        			if((son[y][0]==x)^(son[z][0]==y)) rotate(x,k);
        			else	rotate(y,k);
        		}
        		rotate(x,k);
        	}
        }
        int find(int now,int rk)
        {
        	pushdown(now);
        	int lson=son[now][0],rson=son[now][1];
        	if(siz[lson]+1==rk) return now;
        	if(siz[lson]>=rk) return find(lson,rk);
        	return find(rson,rk-siz[lson]-1);
        }
        void set(int now)
        {
        	if(!now) return;
        	int lson=son[now][0],rson=son[now][1];
        	set(lson);set(rson);q.push(now);//一定要记住push now 
        	fa[now]=son[now][0]=son[now][1]=0;
        	tag[now]=rev[now]=0;
        	return;
        }
        int split(int now,int tot)
        {
        	int x=find(root,now),y=find(root,now+tot+1);
        	splay(x,root);splay(y,son[x][1]);
        	return son[y][0];
        }
        void query(int now,int tot)
        {
        	int x=split(now,tot);
        	printf("%d\n",sum[x]);
        }
        void modify(int now,int tot,int val)
        {
        	int x=split(now,tot),y=fa[x];
        	tag[x]=1;v[x]=val;sum[x]=val*siz[x];
        	if(val>=0)	lx[x]=rx[x]=maxx[x]=sum[x];
        	else	lx[x]=rx[x]=0,maxx[x]=val;
        	pushup(y);pushup(fa[y]);//pushup 一定要记清 
        }
        void reverse(int now,int tot)
        {
        	int x=split(now,tot),y=fa[x];
        	if(!tag[x])
        	{
        		rev[x]^=1;
        		swap(son[x][0],son[x][1]);
        		swap(lx[x],rx[x]);
        		pushup(y);pushup(fa[y]);
        	}
        } 
        void erase(int now,int tot)
        {
        	int x=split(now,tot),y=fa[x];
        	set(x);son[y][0]=0;
        	pushup(y);pushup(fa[y]);
        }
        void build(int l,int r,int flag)
        {
        	if(l>r) return;
        	int mid=(l+r)>>1,now=id[mid],last=id[flag];
        	if(l==r)
        	{
        		sum[now]=a[l];
        		siz[now]=1;
        		tag[now]=rev[now]=0;
        		if(a[l]>0) lx[now]=rx[now]=maxx[now]=a[l];
        		else lx[now]=rx[now]=0,maxx[now]=a[l];
        	}
        	else
        	build(l,mid-1,mid),build(mid+1,r,mid);
        	v[now]=a[mid];fa[now]=last;pushup(now);
        	son[last][mid>=flag]=now;
        }
        void insert(int now,int tot)
        {
        	for(int i=1;i<=tot;i++) scanf("%d",&a[i]);
        	for(int i=1;i<=tot;i++)
        	{
        		if(!q.empty()) id[i]=q.front(),q.pop();
        		else id[i]=++cnt;
        	}
        	build(1,tot,0);
        	int z=id[(1+tot)>>1];
        	int x=find(root,now+1),y=find(root,now+2);
        	splay(x,root);splay(y,son[x][1]);
        	fa[z]=y;son[y][0]=z;
        	pushup(y);pushup(x);
        }
        void out(int now)
        {
        	pushdown(now);
        	int lson=son[now][0],rson=son[now][1];
        	if(lson) out(lson);
        	if(2<=now && now<=n+1)
        	printf("%d ",now-1);
        	if(rson) out(rson);
        }
        int main()
        {
        	scanf("%d%d",&n,&m);
        	maxx[0]=a[1]=a[n+2]=-inf;
        	for(int i=1;i<=n;i++)a[i+1]=i;;
        	for(int i=1;i<=n+2;i++)id[i]=i;
        	build(1,n+2,0);
        	root=(n+3)>>1;cnt=n+2;
        	while(m--)
        	{
        		int l,r;
        		scanf("%d%d",&l,&r);
        		reverse(l,r-l+1);
        	}
        	out(root);
        }
        
    2. Treap(简单好写)

      1. #include<iostream>
        #include<stdio.h>
        #include<string.h>
        #include<algorithm>
        #define maxn 100005
        #define lson (son[now][0])
        #define rson (son[now][1])
        #define mid ((nl+nr)>>1)
        using namespace std;
        int n,m,root;
        int fa[maxn],son[maxn][2],sz[maxn],rev[maxn];
        void pushup(int now)
        {
        	sz[now]=sz[lson]+sz[rson]+1;
        }
        void pushdown(int now)
        {
        	if(rev[now])
        	{
        		swap(lson,rson);
        		rev[lson]^=1; 
        		rev[rson]^=1;
        		rev[now]^=1;
        	}
        }
        void build(int nl,int nr,int pa)
        {
        	if(nl>nr) return;
        	if(nl==nr)
        	{
        		sz[nl]=1; fa[nl]=pa; son[pa][nl>pa]=nl;
        		return;
        	}
        	build(nl,mid-1,mid);
        	build(mid+1,nr,mid);
        	fa[mid]=pa; son[pa][mid>pa]=mid;
        	pushup(mid);
        }
        void rotate(int x,int &k)
        {
        	int y=fa[x],z=fa[y];
        	int l=(son[y][1]==x),r=l^1;
        	if(y==k)
        		k=x;
        	else
        	{
        		if(son[z][0]==y) son[z][0]=x;
        		else son[z][1]=x;
        	}
        	fa[x]=z; fa[son[x][r]]=y; fa[y]=x;
        	son[y][l]=son[x][r]; son[x][r]=y;
        	pushup(y); pushup(x);
        }
        void splay(int x,int &k)
        {
        	while(x!=k)
        	{
        		int y=fa[x],z=fa[y];
        		if(y!=k)
        		{
        			int _=0;
        			if((son[z][0]==y) ^_^ (son[y][0]==x))
        				rotate(x,k);
        			else
        				rotate(y,k);
        		}
        		rotate(x,k);
        	}
        }
        int find(int now,int v)
        {
        //	cerr<<now<<" "<<v<<endl;
        	pushdown(now);
        	if(sz[lson]+1==v) return now;
        	if(sz[lson]+1<v) return find(rson,v-(sz[lson]+1));
        	return find(lson,v);
        }
        void reverse(int l,int r)
        {
        	l=find(root,l);
        	r=find(root,r+2);
        	splay(l,root);
        	splay(r,son[l][1]);
        	rev[son[r][0]]^=1;
        }
        int main()
        {
        	scanf("%d%d",&n,&m);
        	build(1,n+2,0);
        	root=((1+(n+2))>>1);
        	for(int i=1;i<=m;i++)
        	{
        		int l,r;
        		scanf("%d%d",&l,&r);
        		reverse(l,r);
        	}
        	for(int i=2;i<=n+1;i++)
        		printf("%d ",find(root,i)-1);
        }
        
  3. 可持久化平衡树

    1. 和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本。(操作3, 4, 5, 6即保持原版本无变化)

    2. 只能用Treap了

      1. #include<iostream>
        #include<stdio.h>
        #include<string.h>
        #include<stdlib.h>
        #include<algorithm>
        #define maxn 500005*60
        #define lson son[now][0]
        #define rson son[now][1]
        using namespace std;
        const int inf=2147483647;
        typedef pair<int,int> pr;
        int root[maxn],tot,sz[maxn],cnt;
        int son[maxn][2],val[maxn],k[maxn];
        void pushup(int now)
        {
        	sz[now]=sz[lson]+sz[rson]+1;
        }
        int copy(int now)
        {
        	tot++;
        	sz[tot]=sz[now]; son[tot][0]=son[now][0]; son[tot][1]=son[now][1];
        	val[tot]=val[now]; k[tot]=k[now];
        	return tot;
        }
        int merge(int x,int y)
        {
        	if(!x || !y) return x+y;
        	if(k[x]<k[y]) return son[x][1]=merge(son[x][1],y),pushup(x),x;
        	else return son[y][0]=merge(x,son[y][0]),pushup(y),y;
        }
        pr split(int now,int v)
        {
        	if(!now) return pr(0,0);
        	pr y;
        	if(sz[lson]>=v)
        	{
        		int x=copy(now);
        		y=split(lson,v);
        		son[x][0]=y.second;
        		pushup(x);
        		y.second=x;
        	}
        	else
        	{
        		int x=copy(now);
        		y=split(rson,v-sz[lson]-1);
        		son[x][1]=y.first;
        		pushup(x);
        		y.first=x;
        	}
        	return y;
        }
        int find(int ver,int v,int p)
        {
        	pr x=split(root[ver],v-1),y=split(x.second,1);
        	int ans=y.first;
        	if(p==0)
        	root[ver]=merge(merge(x.first,ans),y.second);
        	else
        	root[++cnt]=merge(merge(x.first,ans),y.second);
        	return val[ans];
        }
        int rk(int now,int v)
        {
        	int minn=inf,maxx=0;
        	while(now)
        	{
        		if(val[now]==v) minn=min(minn,maxx+sz[lson]+1);
        		if(v>val[now]) maxx+=sz[lson]+1,now=rson;
        		else now=lson;
        	}
        	return minn==inf ? maxx+1 : minn;
        }
        int insrk(int now,int v)
        {
        	int minn=inf,maxx=0;
        	while(now)
        	{
        		if(val[now]==v) minn=min(minn,maxx+sz[lson]+1);
        		if(v>val[now]) maxx+=sz[lson]+1,now=rson;
        		else now=lson;
        	}
        	return minn==inf ? maxx : minn;
        }
        void insert(int ver,int v)
        {
        	int pos=insrk(root[ver],v);
        	pr x=split(root[ver],pos);
        	sz[++tot]=1; val[tot]=v; k[tot]=rand();
        	root[++cnt]=merge(merge(x.first,tot),x.second);
        }
        void del(int ver,int v)
        {
        	int pos=rk(root[ver],v);
        	if(find(ver,pos,0)!=v)
        	{
        		root[++cnt]=root[ver];
        		return;
        	}
        	pr x=split(root[ver],pos-1),y=split(x.second,1);
        	root[++cnt]=merge(x.first,y.second);
        }
        int suc(int ver,int v)
        {
        	int now=root[ver],ans=inf;
        	while(now)
        	{
        		if(val[now]>v)
        		{
        			ans=min(ans,val[now]);
        			now=lson;
        		}
        		else
        			now=rson;
        	}
        	cnt++;
        	root[cnt]=root[ver];
        	return ans;
        }
        int pre(int ver,int v)
        {
        	int now=root[ver],ans=-inf;
        	while(now)
        	{
        		if(val[now]<v)
        		{
        			ans=max(ans,val[now]);
        			now=rson;
        		}
        		else
        			now=lson;
        	}
        	cnt++;
        	root[cnt]=root[ver];
        	return ans;
        }
        int main()
        {
        	int _;
        	scanf("%d",&_);
        	while(_--)
        	{
        		int ver,op,x;
        		scanf("%d%d%d",&ver,&op,&x);
        		if(op==1)
        			insert(ver,x);
        		if(op==2)
        			del(ver,x);
        		if(op==3)
        		{
        			printf("%d\n",rk(root[ver],x));
        			root[++cnt]=root[ver];
        		}
        		if(op==4)
        			printf("%d\n",find(ver,x,1));
        		if(op==5)
        			printf("%d\n",pre(ver,x));
        		if(op==6)
        			printf("%d\n",suc(ver,x));
        	}
        }
        
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值