首页 > 其他 > 详细

树套树

时间:2019-04-01 22:28:11      阅读:144      评论:0      收藏:0      [点我收藏+]

前言:

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

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

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

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

正文:

线段树套平衡树

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

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

你会怎么办那

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

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

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

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

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

只好吸口氧才过了~~~

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

#include<cstdio>
#include<algorithm>

const int maxn=55555;
#define inf (0x7fffffff)

int get_rand()
{
    static int seed=19260817;
    return seed=(((seed^143857)+200303)*2019)%inf;
}

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);
        }
          
        void build(int l,int r,int *data)
        {
            for(int i=l;i<=r;i++)
                insert(data[i]);
        }

}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) { treap[k].build(l,r,data); if(l!=r) { 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) { 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(x<=l&&y>=r) 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(x<=l&&y>=r) 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(x<=l&&y>=r) 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\n",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\n",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\n",get_pre(1,1,n,x,y,num)); } if(opt==5) { int x,y,num; scanf("%d%d%d",&x,&y,&num); printf("%d\n",get_suf(1,1,n,x,y,num)); } } return 0; }

树状数组套主席树

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

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

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

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

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

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

后序:

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

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

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

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

树套树

原文:https://www.cnblogs.com/Vscoder/p/10639100.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!