zoukankan      html  css  js  c++  java
  • 平衡树 Treap

    //平衡树 Treap
    //维护一个堆使得随机权值小(大)的数始终在上方
    //使用随机权值目的:防止出题人卡 
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    struct uio{
        int l,r,siz,num,rd,tim;//左儿子,右儿子,子树大小+自己大小,点值,随机权值,出现次数 
    }treap[100001];//此代码为小根堆 即随机权值小的在上方 
    int n,size,ans,root;//size树的大小 
    void update(int k)//更新 
    {
        treap[k].siz=treap[treap[k].l].siz+treap[treap[k].r].siz+treap[k].tim;
    }
    void right(int &k)//右旋 
    {
        int x=treap[k].l;
        treap[k].l=treap[x].r;
        treap[x].r=k;
        treap[x].siz=treap[k].siz;
        update(k);
        k=x;
    }
    void left(int &k)//左旋 
    {
        int x=treap[k].r;
        treap[k].r=treap[x].l;
        treap[x].l=k;
        treap[x].siz=treap[k].siz;
        update(k);
        k=x;
    } 
    void insert(int &k,int x)
    {
        if(k==0)//到达叶节点就开始插入
        {
            size++;
            k=size;
            treap[k].siz=1;
            treap[k].tim=1;
            treap[k].num=x;
            treap[k].rd=rand();
            return;
        }
        treap[k].siz++;//插入节点的每个父节点子树大小都加一 
        if(treap[k].num==x)//若已有此节点 
            treap[k].tim++;//出现次数加一 
        else
        {
            if(x>treap[k].num)//在右子树中
            {
                insert(treap[k].r,x);
                if(treap[treap[k].r].rd<treap[k].rd)//子节点随机数比父节点小
                    left(k);//左旋 
            } 
            else//在右子树中 
            {
                insert(treap[k].l,x);
                if(treap[treap[k].l].rd<treap[k].rd)//子节点随机数比父节点小 
                    right(k);//右旋 
            }
        }
    }
    void del(int &k,int x)
    {
        if(k==0)//树中已无节点 
            return;
        if(treap[k].num==x)//找到了 
        {
            if(treap[k].tim>1)//出现次数大于一,直接删除即可 
            {
                treap[k].tim--;
                treap[k].siz--;
                return;
            }
            if(treap[k].l*treap[k].r==0)//左右子树有一棵为空
                k=treap[k].l+treap[k].r;//直接把非空子树接在原树上 
            else
            {
                if(treap[treap[k].l].rd<treap[treap[k].r].rd)//每次下沉时与随机权值小的交换 以确保小根堆性质不变 
                    right(k),del(k,x);
                else left(k),del(k,x);
            }
        }
        else//没找到 
        {
            if(x>treap[k].num)//在右子树中 
            {
                treap[k].siz--;
                del(treap[k].r,x);
            }
            else//在左子树中 
            {
                treap[k].siz--;
                del(treap[k].l,x);
            }
        } 
    }
    int get_no(int k,int x)
    {
        if(k==0)//树中没有节点 
            return 0;
        if(treap[k].num==x)//找到x 
            return treap[treap[k].l].siz+1;//结果为自己加左子树的大小 
        else if(x>treap[k].num)//在右子树 
            return treap[treap[k].l].siz+treap[k].tim+get_no(treap[k].r,x);//结果为递归回的结果加自己的大小加左子树的大小 
        else return get_no(treap[k].l,x);//在左子树  结果为递归回的结果 
    }
    int get_num(int k,int x)
    {
        if(k==0)//树中没有节点 
            return 0;
        if(x<=treap[treap[k].l].siz)//在左子树中
            return get_num(treap[k].l,x);
        else if(x>(treap[treap[k].l].siz+treap[k].tim))//在右子树中
            return get_num(treap[k].r,x-treap[treap[k].l].siz-treap[k].tim);
        else return treap[k].num;//在这个点上
    }
    void pre(int k,int x)
    {
        if(k==0)
            return;
        if(treap[k].num<x)//在右子树中
        {
            ans=k;
            pre(treap[k].r,x); 
        }
        else pre(treap[k].l,x);//在左子树中 
    }
    void nxt(int k,int x)
    {
        if(k==0)
            return;
        if(treap[k].num>x)//在左子树中
        {
            ans=k;
            nxt(treap[k].l,x);
        }
        else nxt(treap[k].r,x);
    } 
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            if(u==1)
                insert(root,v);
            if(u==2)
                del(root,v);
            if(u==3)
                printf("%d
    ",get_no(root,v));
            if(u==4)
                printf("%d
    ",get_num(root,v));
            if(u==5)
            {
                pre(root,v);
                printf("%d
    ",treap[ans].num);
            }
            if(u==6)
            {
                nxt(root,v);
                printf("%d
    ",treap[ans].num);
            }
        }
         return 0;
    }
  • 相关阅读:
    unicode,ascii是一種字符集,而uft是一種編碼方式
    加水印程序
    收錄PHP試題
    window下接裝php+Apache+mysql
    查找字符串程序
    連接兩表sql語句,二種寫法,sql面試題目
    求一組9位數且不重複(19組成),滿足前n位能被n整除,例如:取先二位能被2整除,取先三位能被3整除...取先九位能被9整除。
    php連mssql,access的方法 js連接access數據庫
    asp.net試題(五)
    lamp+vsftp +zend optimizer 配置,需要注意的地方
  • 原文地址:https://www.cnblogs.com/water-radish/p/9280875.html
Copyright © 2011-2022 走看看