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");
    }
}

题目

猜你喜欢

转载自www.cnblogs.com/Lance1ot/p/8909365.html