• 非旋treap


    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define maxn 100005
    struct hh
    {
        int siz;//siz以这个点为根的子树大小 
        int val;//val值满足二叉搜索树的性质(lch<now<rch) 
        int key;//key值满足堆的性质(大堆或小堆) 
        int lch;//lch左子节点
        int rch;//rch右子节点 
    }t[maxn];
    int tot,seed=233,root=1;
    int Rand(); //给k赋予随机优先级 
    inline ll read()//快速读入程序 
    {
        char kr=0;
        char ls;
        for(;ls>'9'||ls<'0';kr=ls,ls=getchar());
        ll xs=0;
        for(;ls>='0'&&ls<='9';ls=getchar())
        {
            xs=xs*10+ls-48;
        }
        if(kr=='-')
        xs=0-xs;
        return xs;
    }
    int Rand()
    {//随机key值 
        return seed=int(seed*482711ll%2147483647);/**/
    }
    int NEW(int val)//新建节点 
    {
        t[++tot].siz=1;
        t[tot].val=val;
        t[tot].key=Rand();
        t[tot].lch=t[tot].rch=0;
        return tot;
    }
    void update(int now)//维护子树大小 
    {
        t[now].siz=t[t[now].lch].siz+t[t[now].rch].siz+1;
    }
    void split(int now,int &a,int &b,int val)//拆分操作 
    {//now为原treap,a为左子树,b为右子树,val为判定值(注意传地址符) 
        if(now==0)
        {
            a=b=0;//若now=0分割完毕 
            return ;
        }
        if(t[now].val<=val)//因为now左子树中的所有值都小于now的值,所以若now属于左子树,那么他们都属于左树递归now的右子树;
        a=now,split(t[now].rch,t[a].rch,b,val);//a=now已经使a的右子树=now的右子树,不再递归a的右子树; 
        else//同上now的右子树也都属于左树,递归左子树; 
        b=now,split(t[now].lch,a,t[b].lch,val);
        update(now);//因为后面会用到左(右)树的siz所以更新维护 
    }
    void merge(int &now,int a,int b)//合并操作,now新树 
    {
        if(a==0||b==0)
        {
            now=a+b;//若某个数已空,则将另一个子树整体插入 
            return ;
        }
        //按照key值合并(堆性质)
        if(t[a].key<t[b].key)
        //若a树key值<b树,那么b树属于a树的后代,因为b树恒大于a树,那么b树一定属于a树的右后代,a的左子树不变,直接赋值给now,递归合并a的右子树和b
        now=a,merge(t[now].rch,t[a].rch,b); 
        else//同理,a树一定是b树的左儿子,递归合并b的右子树和a 
        now=b,merge(t[now].lch,a,t[b].lch);
        update(now);//维护一下合并后的树的大小 (siz)
    }
    void insert(int val)//插入一个数 
    {
        int x=0,y=0,z;
        z=NEW(val);//新建节点z,作为z树
        split(root,x,y,val);//将树分为两部分,x树为<=待插入的值,y树大于 
        merge(x,x,z);//合并x树和新节点z(树),赋值给x树 
        merge(root,x,y);//合并新x树和y树,赋值给根 
    }
    void delet(int val)//删除一个数 
    {
        int x=0,y=0,z=0;
        split(root,x,y,val);//分为x树为<=待删除,y树大于 
        split(x,x,z,val-1);//x树分为新x树<待删除,z树等于待删除
        merge(z,t[z].lch,t[z].rch);//合并z树的左右儿子,赋给z树,即丢弃z树的根节点(实现删除) 
        merge(x,x,z);
        merge(root,x,y);//合并,不再重复 
    }
    void get_rank(int val)//求k数的排名 
    {
        int x=0,y=0;
        split(root,x,y,val-1);//分为小于待查找的x树和大于等于的y树 
        printf("%d
    ",t[x].siz+1);//即为待查找值的编号
        merge(root,x,y);//合并 
    }
    void find(int now,int rank)//兼容 
    {//兼容性函数->用来 查询排名第k位的数,查询k的前驱、后继
        while(t[t[now].lch].siz+1!=rank)
        {
            if(t[t[now].lch].siz>=rank)
                now=t[now].lch;//若左子树大小大于rank,找左子树
            else 
            {
                rank-=(t[t[now].lch].siz+1),now=t[now].rch;
                //找右子树(rank-左子树大小-树根(大小为1))号的元素
            } 
        }
        printf("%d
    ",t[now].val);
    }
    void get_val(int rank)//求排名第k为的数 
    {
        find(root,rank);//find查找即可
    }
    void get_pre(int val)//求k的前驱
    {
        int x=0,y=0;
        split(root,x,y,val-1);//x树为<=val-1值即小于val值 
        find(x,t[x].siz);//在小于val值中找到最大的(编号为siz)就是前驱
        merge(root,x,y);//合并 
    }
    void get_nxt(int val)
    {
        int x=0,y=0;
        split(root,x,y,val);//x树小于等于val值,那么y树大于val值
        find(y,1);//在y树中找最小的,即为后继
        merge(root,x,y);//合并 
    }
    int main()
    {
        int i,j,k,m;
        NEW(2147483627);//初始化虚节点 
        t[1].siz=0;//siz为0,不算虚节点的大小
        m=read(); 
        while(m--)
        {
            j=read();k=read();
            if(j==1) insert(k);//插入一个数k 
            if(j==2) delet(k);//删除一个数k 
            if(j==3) get_rank(k);//查询k数的排名
            if(j==4) get_val(k);//查询排名第k位的数 
            if(j==5) get_pre(k);//求k的前驱(定义为小于x,且为最大的数)
            if(j==6) get_nxt(k);//求k的后继(定义为大于x,且为最小的数) 
        }
        return 0;
    }
  • 相关阅读:
    卡特兰数列(蒟蒻的学习笔记)
    10月7日 蒟蒻的流水账
    10月6日 蒟蒻的流水账
    10月5日 蒟蒻的流水账
    10月4号 蒟蒻的流水账
    2017 10 14(吐槽初赛)
    2017 10 13
    个人介绍
    luogu P1156 垃圾陷阱
    模板之矩阵快速幂(luogu P3390【模板】矩阵快速幂)
  • 原文地址:https://www.cnblogs.com/lck-lck/p/9546219.html
Copyright © 2020-2023  润新知