treap

玄学treap

看脸算法

指针真垃圾

delete 真垃圾

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<ctime>
using namespace std;
struct node
{
	int v;
	int num;//有可能有多个相同的数在一棵BST中
	int r;
	int s;
	node* ch[2];//左右孩子
	node(int val):v(val)//初始化
	{
		r=rand();
		num=1;
		s=1;
		ch[0]=ch[1]=NULL;
	}
	int cmp(int val)//比较函数
	{
		if(val==v)
			return -1;
		if(val<v)
			return 0;
		else
			return 1;
	}
	void sum()//计算节点个数
	{
		s=num;
		if(ch[0]!=NULL)
			s+=ch[0]->s;
		if(ch[1]!=NULL)
			s+=ch[1]->s;
	}
};
void rotato(node* &x,int mode)//旋转函数,mode为左右旋参数
{
	node* k=x->ch[mode^1];//相当于1-mode,不过有常数加成
	x->ch[mode^1]=k->ch[mode];
	k->ch[mode]=x;
	x->sum();//重新计算节点个数
	k->sum();
	x=k;
}
void insert(node* &x,int val)//插入,一定要引用,不然旋转就没用了
{
	if(x==NULL)
	{
		x=new node(val);
		return ;
	}
	//printf("%d ",x->v);
	int d=x->cmp(val);//还是自己看cmp的返回值吧
	if(d==-1)
	{
		x->num+=1;
		x->s+=1;
		return ;
	}
	else
	{
		insert(x->ch[d],val);//递归插入
		if(x->ch[d]->r > x->r)//如果不满足堆性质,旋转
			rotato(x,d^1);
	}
	x->sum();//重新计算个数
}
void remove(node* &x,int val)
{
	if(x==NULL)
		return ;
	int d=x->cmp(val);
	if(d==-1)
	{
		if(x->num>1)
		{
			x->num-=1;
			x->s-=1;
			return ;
		}
		node* u=x;
		if(x->ch[0]!=NULL&&x->ch[1]!=NULL)//如果左右儿子都有,那样的话,我们把根节点和左右儿子中优先度最大的旋上来。直到要删除的值最多只有一个左右儿子,然后直接删除。
		{
			int d2=( x->ch[0]->r > x->ch[1]->r ? 1 : 0);
			rotato(x,d2);
			remove(x->ch[d2],val);
		}
		else
			if(x->ch[0]==NULL)
				x=x->ch[1];
			else
				x=x->ch[0];
		//delete u; delete就是个垃圾
	}
	else
		remove(x->ch[d],val);
	if(x!=NULL)
		x->sum();
}
int kth(node *x,int k)//第几小的数
{
    if (k<0||k>x->s||x==NULL)
		return 0;
	int s=(x->ch[0]==NULL ? 0 : x->ch[0]->s);
	if(s<k&&k<=s+x->num)//照着规律查就行了。
		return x->v;
	if(k<=s)
		return kth(x->ch[0],k);
	else
		return kth(x->ch[1],k-s-x->num);//在这停顿
}
int find(node *x,int val)//val的排名
{
	int d=x->cmp(val);
	int s=(x->ch[0]==NULL ? 0 : x->ch[0]->s);
	if(d==-1)
		return s+1;
	else
	{
		if(d==0)
			return find(x->ch[0],val);
		else
			return s+x->num+find(x->ch[1],val);
	}
}
void pre(node* x,int val,int &ans)//前驱与后继
{
    if(x==NULL)
		return;
    if(x->v<val) //根节点小于val
    {
        if(x->v>ans)//更新一下
			ans=x->v;
        if(x->ch[1]!=NULL) //遍历右子树就可以了,左子树就不用遍历了
			pre(x->ch[1],val,ans);
    }
	else
	    if(x->v>=val)
	        if(x->ch[0]!=NULL)//这种情况就只遍历左子树就可以了
				pre(x->ch[0],val,ans);
}
void nxt(node* x,int val,int &ans)
{
    if(x==NULL)
		return;
    if(x->v>val)
    {
        if(x->v<ans)
			ans=x->v;
        if(x->ch[0]!=NULL)
			nxt(x->ch[0],val,ans);
    }
	else
	    if(x->v<=val)
	        if (x->ch[1]!=NULL)
				nxt(x->ch[1],val,ans);
}
int read()
{
	int s=0,f=1;
	char in=getchar();
	while(in<'0'||in>'9')
	{
		if(in=='-')
			f=-1;
		in=getchar();
	}
	while(in>='0'&&in<='9')
	{
		s=(s<<1)+(s<<3)+in-'0';
		in=getchar();
	}
	return s*f;
}
void visit(node *x)
{
	if(x==NULL)
		return ;
	visit(x->ch[0]);
	printf("%d ",x->v);
	visit(x->ch[1]);
}//中序遍历
node *root;
int main()
{
	srand(time(NULL));
	int n=read();
	int a,b;
	int ans;
	for(int i=1;i<=n;i++)
	{
		a=read();
		b=read();
		switch(a)
		{
			case 1:insert(root,b);break;
			case 2:remove(root,b);break;
			case 3:printf("%d\n",find(root,b));break;
			case 4:printf("%d\n",kth(root,b));break;
			case 5:insert(root,b);ans=-0x7fffffff;pre(root,b,ans);printf("%d\n",ans);remove(root,b);break;
			case 6:insert(root,b);ans=0x7fffffff;nxt(root,b,ans);printf("%d\n",ans);remove(root,b);break;
		}
		//visit(root);
		//printf("\n");
	}
}

题目

posted @ 2018-04-22 20:43  Lance1ot  阅读(196)  评论(0编辑  收藏  举报