zkw Splay学习笔记

最近。。

最近心里颇不平静。

最近花了三天时间学了zkw Splay,发现这玩意儿真TM难写;加上各种Code Trick也还是写了好久,还有各种错误,一直在炸。

一些心得:

①维护size时不需要考虑太多东西,只需要改变孩子指针后直接用孩子的size维护即可,注意要在两个地方维护:

旋转的时候维护;

翻转子树链表的时候维护。

②zkw Splay中左临时树是一些没有右孩子子树的节点,然后。。为了方便(真的方便么。。),我们可以一开始用每棵子树的右儿子存储它的父节点,然后再把根表反转。

反转真是一件蛋疼的事,注意到新根也还是有左右子树的,所以其实就相当于从一个根表的表头加入另一个根表的表头。(!!这玩意儿我想了好久才想明白,真是坑爹。)

③Select中向下探测两层真的是一件很蛋疼的事,我是通过人工让两层不一样以解决在下一层取到所需节点的问题的。

④最重要的:一定要时刻注意变量的意义!它改变了没有?它现在是什么!尤其是在坑爹的表头插入和维护的时候。。经常弄错导致炸飞。

⑤zkw。。真是太牛了!我感觉我现在的代码能力还不太能驾驭得了zkw Splay。。以后如果没有被卡就还是都老老实实写普通Splay吧。。

代码(模板题-普通平衡树):

#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
#include<algorithm>
struct SS{
	SS * c[2];
	int key,num,size;
}* null=new SS((SS){null,null,0,0,0}),* root=new SS((SS){null,null,0x7fffffff,1,1}),* newroot=new SS((SS){null,null,0,0,0});
inline void mtn(){
	SS * now,* next;
	for(int D=0;D<2;++D)
		for(now=newroot->c[D];now!=null;now=next){
			next=now->c[D];
			now->c[D]=root->c[!D];
			root->c[!D]=now;
			now->size=now->c[0]->size+now->c[1]->size+now->num;
		}
	root->size=root->c[0]->size+root->c[1]->size+root->num;
	newroot->c[0]=null;
	newroot->c[1]=null;
}
inline void search(int A){
	bool D;
	SS * tmp;
	while(root->key!=A){
		D=root->key<A;
		if(root==null){
			root=new SS((SS){null,null,A,0,0});
			break;
		}
		if(root->c[D]!=null&&root->c[D]->key!=A&&D==(root->c[D]->key<A)){
			tmp=root->c[D];
			root->c[D]=tmp->c[!D];
			tmp->c[!D]=root;
			root->size=root->c[0]->size+root->c[1]->size+root->num;
			root=tmp;
		}
		if(root==null){
			root=new SS((SS){null,null,A,0,0});
			break;
		}
		tmp=root->c[D];
		root->c[D]=newroot->c[D];
		newroot->c[D]=root;
		root=tmp;
	}
	mtn();
}
inline void select(int A){
	bool D,d;
	SS * tmp;
	while(1){
		D=root->size-root->c[1]->size<A;
		if(!D&&root->c[0]->size<A)break;
		if(D)A-=root->size-root->c[1]->size;
		
		if(root->c[D]->c[0]->size<A&&root->c[D]->size-root->c[D]->c[1]->size>=A)d=!D;
		else d=root->c[D]->size-root->c[D]->c[1]->size<A;
		
		if(D==d){
			if(d)A-=root->c[1]->size-root->c[1]->c[1]->size;
			tmp=root->c[D];
			root->c[D]=tmp->c[!D];
			tmp->c[!D]=root;
			root->size=root->c[0]->size+root->c[1]->size+root->num;
			root=tmp;
		}
		tmp=root->c[D];
		root->c[D]=newroot->c[D];
		newroot->c[D]=root;
		root=tmp;
	}
	mtn();
}
char * ptr=(char *)malloc(2000000);
inline void in(int &x){
	bool flag=0;
	while(*ptr<'0'||*ptr>'9')
		if(*ptr++=='-')
			flag=1;
	x=0;
	while(*ptr>47&&*ptr<58)x=x*10+*ptr++-'0';
	if(flag)x=-x;
}
int main(){
	freopen("phs.in","r",stdin);
	freopen("phs.out","w",stdout);
	fread(ptr,1,2000000,stdin);
	int N,ans,opt,x;
	in(N);
	SS * tmp;
	while(N--){
		in(opt),in(x);
		switch(opt){
			case 1:
				search(x);
				++root->num;
				++root->size;
				break;
			case 2:
				search(x);
				if(!--root->num){
					tmp=root;
					root=root->c[1];
					select(1);
					root->c[0]=tmp->c[0];
					root->size+=root->c[0]->size;
					delete tmp;
				}
				else --root->size;
				break;
			case 3:
				search(x);
				printf("%d\n",root->c[0]->size+1);
				break;
			case 4:
				select(x);
				printf("%d\n",root->key);
				break;
			case 5:
				ans=-0x7fffffff;
				tmp=root;
				while(tmp!=null)
					if(tmp->key>=x)
						tmp=tmp->c[0];
					else{
						ans=max(tmp->key,ans);
						tmp=tmp->c[1];
					}
				printf("%d\n",ans);
				break;
			case 6:
				ans=0x7fffffff;
				tmp=root;
				while(tmp!=null)
					if(tmp->key<=x)
						tmp=tmp->c[1];
					else{
						ans=min(tmp->key,ans);
						tmp=tmp->c[0];
					}
				printf("%d\n",ans);
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值