• 树套树


    前言:

    什么,你说线段树码量大?那来写平衡树吧~~~

    什么,你又说平衡树码量大?那来写树套树吧~~~

    如果你想,可以将以前学过的数据结构自由组合一下

    不过经常会用到的只有两种——线段树套平衡树和树状数组套主席树

    正文:

    线段树套平衡树

    假设你对平衡树的各种操作已经很熟练了(你为什么那么熟练~~~)

    那么如果要你写一种数据结构支持查询区间排名,区间前驱,区间后继等

    你会怎么办那

    提到区间操作,很容易就会想到线段树

    所以我们可以线段树套平衡树啊(当然也可以线段树套线段树)

    没错,就是这么简单(真香~~~)

    不过我写了好久,可能是因为它码量小

    无奈被某谷数据卡常(题目来自洛谷P3380

    只好吸口氧才过了~~~

    这里我套的是 $fhq treap$ ,模板在这里

    #include<cstdio>
    #include<algorithm>
    
    const int maxn=55555;
    #define inf (0x7fffffff)
    
    int get_rand()
    {
        static int seed=19260817;
        return seed=(((seed^142857)+200303)*2019)%0x3f3f3f3f;
    }
    
    struct node
    {
        int son[2];
        int w,key,size;
        node(){}
        node(int w):w(w)
        {
            size=1;
            key=get_rand();
            son[0]=0,son[1]=0;
        }
    };
    
    int tree_cnt;
    node tree[maxn*4*18];
    
    class fhq_treap
    {
    
        private:
    
            int root;
            
            int newnode(int w)
            {
                tree[++tree_cnt]=node(w);
                return tree_cnt;
            }
            
            void update(int now)
            {
                tree[now].size=tree[tree[now].son[0]].size+tree[tree[now].son[1]].size+1;
            }
    
            void split(int now,int num,int &x,int &y)
            {
                if(!now)
                {
                    x=0,y=0;
                    return;
                }
                if(tree[now].w<=num)
                {
                    x=now;
                    split(tree[now].son[1],num,tree[now].son[1],y);
                }
                else
                {
                    y=now;
                    split(tree[now].son[0],num,x,tree[now].son[0]);
                }
                update(now);
            }
    
            int merge(int x,int y)
            {
                if(!x||!y) return x+y;
                if(tree[x].key<tree[y].key)
                {
                    tree[x].son[1]=merge(tree[x].son[1],y);
                    update(x);
                    return x;
                }
                else
                {
                    tree[y].son[0]=merge(x,tree[y].son[0]);
                    update(y);
                    return y;
                }
            }
    
       public:
    
            fhq_treap():root(0){}
    
            void insert(int num)
            {
                int x,y;
                split(root,num,x,y);
                root=merge(merge(x,newnode(num)),y);
            }
    
            void remove(int num)
            {
                int x,y,z;
                split(root,num,x,z);
                split(x,num-1,x,y);
                y=merge(tree[y].son[0],tree[y].son[1]);
                root=merge(merge(x,y),z);
            }
    
            int get_rank(int num)
            {
                int x,y;
                split(root,num-1,x,y);
                int rank=tree[x].size+1;
                root=merge(x,y);
                return rank;
            }
    
            int get_kth(int k)
            {
                int now=root,flag=0;
                while(now)
                {
                    int left_size=tree[tree[now].son[0]].size;
                    if(k<=left_size) now=tree[now].son[0],flag=0;
                    else if(k>left_size+1) k-=left_size+1,now=tree[now].son[1],flag=1;
                    else return tree[now].w;
                }
                return flag?inf:-inf;
            }
    
            int get_pre(int num)
            {
                int rank=get_rank(num);
                return get_kth(rank-1);
            }
    
            int get_suf(int num)
            {
                int rank=get_rank(num+1);
                return get_kth(rank);
            }
    
    }treap[maxn<<2];
    
    int n,m;
    int data[maxn];
    
    #define left(x) (x<<1)
    #define right(x) (x<<1|1)
    
    void build(int k,int l,int r)
    {
        for(int i=l;i<=r;i++)
            treap[k].insert(data[i]);
        if(l==r) return;
        int mid=(l+r)>>1;
        build(left(k),l,mid);
        build(right(k),mid+1,r);
    }
    
    void update(int k,int l,int r,int pos,int num)
    {
        treap[k].remove(data[pos]);
        treap[k].insert(num);
        if(l==r) return;
        int mid=(l+r)>>1;
        if(pos<=mid) update(left(k),l,mid,pos,num);
        else update(right(k),mid+1,r,pos,num);
    }
    
    int get_rank(int k,int l,int r,int x,int y,int num)
    {
        if(l>y||r<x) return 0;
        if(l>=x&&r<=y) return treap[k].get_rank(num)-1;
        int mid=(l+r)>>1;
        return get_rank(left(k),l,mid,x,y,num)+get_rank(right(k),mid+1,r,x,y,num);
    }
    
    int get_kth(int x,int y,int k)
    {
        int l=0,r=inf,ans=-1;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(get_rank(1,1,n,x,y,mid)+1<=k) ans=mid,l=mid+1;
            else r=mid-1;
        }
        return ans;
    }
    
    int get_pre(int k,int l,int r,int x,int y,int num)
    {
        if(l>y||r<x) return -inf;
        if(l>=x&&r<=y) return treap[k].get_pre(num);
        int mid=(l+r)>>1;
        return std::max(get_pre(left(k),l,mid,x,y,num),get_pre(right(k),mid+1,r,x,y,num));
    }
    
    int get_suf(int k,int l,int r,int x,int y,int num)
    {
        if(l>y||r<x) return inf;
        if(l>=x&&r<=y) return treap[k].get_suf(num);
        int mid=(l+r)>>1;
        return std::min(get_suf(left(k),l,mid,x,y,num),get_suf(right(k),mid+1,r,x,y,num));
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&data[i]);
        build(1,1,n);
        for(int i=1,opt;i<=m;i++)
        {
            scanf("%d",&opt);
            if(opt==1)
            {
                int x,y,num;
                scanf("%d%d%d",&x,&y,&num);
                printf("%d
    ",get_rank(1,1,n,x,y,num)+1);
            }
            if(opt==2)
            {
                int x,y,k;
                scanf("%d%d%d",&x,&y,&k);
                printf("%d
    ",get_kth(x,y,k));
            }
            if(opt==3)
            {
                int pos,num;
                scanf("%d%d",&pos,&num);
                update(1,1,n,pos,num);
                data[pos]=num;
            }
            if(opt==4)
            {
                int x,y,num;
                scanf("%d%d%d",&x,&y,&num);
                printf("%d
    ",get_pre(1,1,n,x,y,num));
            }
            if(opt==5)
            {
                int x,y,num;
                scanf("%d%d%d",&x,&y,&num);
                printf("%d
    ",get_suf(1,1,n,x,y,num));
            }
        }
        return 0;
    }

    树状数组套主席树

    假设你对主席树已经很熟悉了

    那么如果要你写一种数据结构支持查询动态区间第 $k$ 大

    你又会怎么办那(数据保证线段树套平衡树不可过)

    显然我们需要一种更优的做法

    于是我们选择树状数组套主席树

    $ps:$ 我还不会......

    后序:

    是不是感觉树套树还挺简单的

    写完了树套树,你就可以写树套树套树

    如果你还不满意,甚至可以写树套树套树套树套树套树套树

    只要你有时间,我没意见的(逃~~~)

  • 相关阅读:
    Django项目:CRM(客户关系管理系统)--20--12PerfectCRM实现King_admin分页上下页
    Django项目:CRM(客户关系管理系统)--19--11PerfectCRM实现King_admin分页显示条数
    Django项目:CRM(客户关系管理系统)--18--10PerfectCRM实现King_admin日期优化
    Django项目:CRM(客户关系管理系统)--17--09PerfectCRM实现King_admin显示注册表的内容
    Oracle数据库,非空约束、主键约束、外键约束、唯一约束

    Oracle数据库,用户的创建及表的创建
    点击时显示遮罩层,登录时灰色遮罩效果
    多个视频时,利用函数实现播放一个,其他自动暂停
    正则表达式、事件调用
  • 原文地址:https://www.cnblogs.com/Vscoder/p/10639100.html
Copyright © 2020-2023  润新知