非旋Treap

    Treap是一种动态树,其主要操作是旋转rotate,不过我比较喜欢splay(附上链接可以看看哦kkkkk),而这样就不能支持持久化了

为了强行优化这一点,我们决定将其转化为静态的Treap,每插入一个新的数据,都先复制上一个版本,再进行修改,这样会极大的

节省空间。我们采取使用随机权值fix来强行修改树的结构,降低树的深度,变成了log,这样,就在持久化的同时进行了优化

#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<string>
#define lc(x) ch[x][0]
#define rc(x) ch[x][1]
#define N 300010
#define M (N*50)

using namespace std;

typedef pair <int ,int > dat;//代表分裂后两颗子树的根节点编号
int ch[M][2],val[M],siz[M],fix[M];//val维护BST的性质,fix维护斜堆的性质 
int cnt=0,n,rt[N];//rt维护的是第t个版本的平衡树的根节点 

inline int Read()
{
	int num=0,k=1;
	char c=getchar();
	while(c!='-'&&(c<'0'||c>'9')) c=getchar();
	if(c=='-'){k=-1;c=getchar();}
	while(c>='0'&&c<='9'){num=(num<<1)+(num<<3)+(c^48);c=getchar();}
	return num*k;
}

inline void Copy (int a,int b) //维护可持久化 
{
	val[a]=val[b];siz[a]=siz[b];
	ch[a][0]=ch[b][0];ch[a][1]=ch[b][1];
	fix[a]=fix[b];
}

inline void push_up(int o)//进行了分裂上传标记 
{
	siz[o]=siz[lc(o)]+siz[rc(o)]+1;
}

inline int New_node (int x=0)//插入新节点 ,如果未传入参数那么默认为0 
{
	val[++cnt]=x;
	siz[cnt]=1;
	ch[cnt][0]=ch[cnt][1]=0;
	fix[cnt]=rand()%5000;//维护一份随机因子 
	return cnt;
}

inline int merge(int a,int b)//利用fix强行维护堆的性质,判断依据是其fix值 
{                              //但实际上我们同时维护了BST的性质,这就是为什么合并到左右子树会有区别 
	if(!a || !b) return a+b;
	int x=++cnt;
	if(fix[a]<fix[b])
	{
		Copy(x,a);
		ch[x][1]=merge(ch[x][1],b);
	}
	else 
	{
		Copy(x,b);
		ch[x][0]=merge(a,ch[x][0]);
	}
	push_up(x);
	return x;
}

inline dat split(int o,int k)//将以o为节点的树分裂,k就相当于是拆分出来的左子树的大小,返回的是两颗子树的根节点编号 
{
	if(!o) return make_pair(0,0);//上一个结点已经是叶子结点 
	int x=++cnt;//建立新节点 
	Copy(x,o);
	dat t;
	if(k<=siz[lc(x)])
	{
		t=split(lc(x),k);
		ch[x][0]=t.second;
		push_up(x);
		return make_pair(t.first,x);
	}
	else 
	{
		t=split(rc(x),k-siz[lc(x)]-1);
		ch[x][1]=t.first;
		push_up(x);
		return make_pair(x,t.second);
	}
} 

inline int  insert(int o,int k,int x)
{
	dat t=split(o,k-1);//先把前k-1分裂出来 
	int tmp=New_node(x);
	int ret=merge(merge(t.first,tmp),t.second);
	return ret;//返回新版本根节点编号 
}

inline int del(int o,int k)
{
	dat a=split(o,k-1);
	dat b=split(a.second,1);
	return merge(a.first,b.second);
}

inline int No_k(int o,int k)//k为当前子树大小 
{
	if(!o)return 0;
	if(k==siz[lc(o)]+1) return val[o];//当前子树根节点 
	if(k<=siz[lc(o)])return No_k(lc(o),k);
	return No_k(rc(o),k-siz[lc(o)]-1);
}

/*inline void dfs(int o)
{
	if(!o) return;
	dfs(lc(o));
	printf("%d ",val[o]);
	dfs(rc(o));
}*/

int main()
{
    int tot=0;
	rt[0]=0;
	n=Read();
	
	for(int i=1;i<=n;i++)
	{
		int op,t,k,x;
		op=Read();t=Read();k=Read();
		if(op==1) x=Read();
		switch(op)
		{
			case 1:{rt[++tot]=insert(rt[t],k,x);break;}
			case 2:{rt[++tot]=del(rt[t],k);break;}
			case 3:{printf("%d\n",No_k(rt[t],k));break;}
		}
	}
	return 0;
}

  

posted @ 2020-11-13 21:29  Roy0_0  阅读(105)  评论(0编辑  收藏  举报
Live2D