zoukankan      html  css  js  c++  java
  • 非旋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;
    }
  • 相关阅读:
    Apache Ant 1.9.1 版发布
    Apache Subversion 1.8.0rc2 发布
    GNU Gatekeeper 3.3 发布,网关守护管理
    Jekyll 1.0 发布,Ruby 的静态网站生成器
    R语言 3.0.1 源码已经提交到 Github
    SymmetricDS 3.4.0 发布,数据同步和复制
    beego 0.6.0 版本发布,Go 应用框架
    Doxygen 1.8.4 发布,文档生成工具
    SunshineCRM 20130518发布,附带更新说明
    Semplice Linux 4 发布,轻量级发行版
  • 原文地址:https://www.cnblogs.com/lck-lck/p/9546219.html
Copyright © 2011-2022 走看看