• 平衡树与可持久化treap


    平衡树(二叉树)

    线段树不支持插入or删除一个数于是平衡树产生了 
    常见平衡树:treap(比sbt慢,好写吧),SBT(快,比较好写,有些功能不支持),splay(特别慢,复杂度当做根号n来用,功能强大,不好写),rbt(红黑树,特别快),//替罪羊树,朝鲜树 
    晚上要讲的不旋转平衡树:

     

    平衡树:

    节点的左儿子中的每一个一定比他小,右儿子中的每一个一定比他大 
    那么它的中序遍历是有序的 
    用下标建树,那么区间询问的话就是求一棵子数和子树根和领一棵子数的一部分

     

    treap:

    tree+heap,平衡树和heap的性质是矛盾的,所以每个节点存一个key和value 
    key值满足heap性质,value满足平衡树的性质,这样的树叫做treap?

     

    插入:

    插入的新节点的key值随机,调用rand函数(这样保证树的深度一定是logn的)改变树的形态使它重新满足hea与平衡树性质

     

    操作1.merge:

    merge(P1,P2):把以p1为根的treap和以p2为根的treap合并成一个treap(p1中的所有制小于

     

    操作2.splays:

    把以p为根的treap中拿出k小的数,组成一个新treap 
    保证原先树中的所有数>新树中所有数

     

    可持久化treap :

     

    插:

    建一个只有一个点的树(要插得数)例如(2.33)把(1,2)splay出来,再把新树(2.33)和(1,2)merge起来,再把(1,2,2.33)和(4,5)merge 一下

     

    删除一个:

    如删除(2.33),先把split(treap,3),此时把splay把(1,2)与(2.33,4,5)分离在split(treep2,1),此时(2.33)与(4,5)分离 
    在merge(treap1,treap3)合并即把(1,2),(4,5)合并,那么2.33就没了

     

    实际操作

    merge时,找key值最大的作为新treap的根,不是p1就是p2 
    1要是p1.p>=p2.p此时p1作为新根,那么p1的左儿子不会变换,右子树就是p1的右子树和p2 merge 一下,即 merge(p1.r,p2); 
    2要是p2.p>p1.p此时p2作为新根,那么p2的右儿子不会变换,左儿子就是p2的 
    左子树 和 p1 mege 一下 即 merge(p2.l,p1); 
    split(p,k)几点记录value,key,l,r,size 
    p.L<-p->p.r; 
    1.要是k<=p.l.size 说明k小的点全在左子数,递归split(p.l,k);构成新树的时候直接把split后剩下的左子树接到P根上就好了 
    2.k=p.l.size+1;,返回两棵树(p.l-p,p.r) 
    3.k>p.l.siz+1,左边已经全不要,那么就split(p.r,k-p.l.size-1); 
    返回两棵树(p.l-p-p.r,剩余p.r)

     

    merge:

    int merge(int p1,int p2) {
        if(!p1)return p2;//zuo bian kong le
        if(!p2)return p1;//you bian kong le
        if(z[p1].key<z[p2].key) {
            z[p1].r=merge(z[p1].r,p2);
            return p1;
        }
        else {
            z[p2].l=merge(z[p2].l,p1);
            return p2
        }
    
     

    split:

    pair<int,int>split(int p,int n) {
        if(z[z[p].l].size>=n) {
            if(!)
        }
        else {
            if(z[p].r==0)return pair(p,0);
            else {
                pair<int,int>px=split(z[p].r,n-z[z[p].l].size-1)
                z[p].r=px.frist;
                int pr=px.second;
                return make_pair(p,pr);
                }
        }
    }
    
     

    query_min:

    查询那些数比x数小,当找到一个根节点比x小时,那么该节点的所有子树都比他小,那么就把子树size+1加到答案里-->删除一个数的时候时用来确定split的k(比要删除的数小的)值

    DAY3

    未分类


    在此输入正文

     

    T3

    g[i][j]表示在第i棵树中其他点到到j的距离和 
    设第i棵树是由第j颗和第k颗合并来的那么g[i][p]=g[j][p]+dis[j][p1][p2](在第j棵树中p1p2的距离)*size(k) 
    g肯定不能用普通数组+普通动态规划求解,记忆花搜索+map只求交点处的那个点的g[X][P]就好了 
    关于dis的求法 
    1.p1,p2在一棵树中时,dis[i][p1][p2]=dis[j][p1][p1] 
    2.不在同一棵树中,dis[j][p1][p3]+l+dis[k][p2][p4]

    #ifdef WIN32
    #define lld "I64d"
    #else 
    #define lld "%lld"
    #endif
    
     

    夜晚

     

    平衡树(二叉树)

    线段树不支持插入or删除一个数于是平衡树产生了 
    常见平衡树:treap(比sbt慢,好写吧),SBT(快,比较好写,有些功能不支持),splay(特别慢,复杂度当做根号n来用,功能强大,不好写),rbt(红黑树,特别快),//替罪羊树,朝鲜树 
    晚上要讲的不旋转平衡树:

     

    平衡树:

    节点的左儿子中的每一个一定比他小,右儿子中的每一个一定比他大 
    那么它的中序遍历是有序的 
    用下标建树,那么区间询问的话就是求一棵子数和子树根和领一棵子数的一部分

     

    treap:

    tree+heap,平衡树和heap的性质是矛盾的,所以每个节点存一个key和value 
    key值满足heap性质,value满足平衡树的性质,这样的树叫做treap?

     

    插入:

    插入的新节点的key值随机,调用rand函数(这样保证树的深度一定是logn的)改变树的形态使它重新满足hea与平衡树性质

     

    操作1.merge:

    merge(P1,P2):把以p1为根的treap和以p2为根的treap合并成一个treap(p1中的所有制小于

     

    操作2.splays:

    把以p为根的treap中拿出k小的数,组成一个新treap 
    保证原先树中的所有数>新树中所有数

     

    可持久化treap :

     

    插:

    建一个只有一个点的树(要插得数)例如(2.33)把(1,2)splay出来,再把新树(2.33)和(1,2)merge起来,再把(1,2,2.33)和(4,5)merge 一下

     

    删除一个:

    如删除(2.33),先把split(treap,3),此时把splay把(1,2)与(2.33,4,5)分离在split(treep2,1),此时(2.33)与(4,5)分离 
    在merge(treap1,treap3)合并即把(1,2),(4,5)合并,那么2.33就没了

     

    实际操作

    merge时,找key值最大的作为新treap的根,不是p1就是p2 
    1要是p1.p>=p2.p此时p1作为新根,那么p1的左儿子不会变换,右子树就是p1的右子树和p2 merge 一下,即 merge(p1.r,p2); 
    2要是p2.p>p1.p此时p2作为新根,那么p2的右儿子不会变换,左儿子就是p2的 
    左子树 和 p1 mege 一下 即 merge(p2.l,p1); 
    split(p,k)几点记录value,key,l,r,size 
    p.L<-p->p.r; 
    1.要是k<=p.l.size 说明k小的点全在左子数,递归split(p.l,k);构成新树的时候直接把split后剩下的左子树接到P根上就好了 
    2.k=p.l.size+1;,返回两棵树(p.l-p,p.r) 
    3.k>p.l.siz+1,左边已经全不要,那么就split(p.r,k-p.l.size-1); 
    返回两棵树(p.l-p-p.r,剩余p.r)

     

    merge:

    int merge(int p1,int p2) {
        if(!p1)return p2;//zuo bian kong le
        if(!p2)return p1;//you bian kong le
        if(z[p1].key<z[p2].key) {
            z[p1].r=merge(z[p1].r,p2);
            return p1;
        }
        else {
            z[p2].l=merge(z[p2].l,p1);
            return p2
        }
    
     

    split:

    pair<int,int>split(int p,int n) {
        if(z[z[p].l].size>=n) {
            if(!)
        }
        else {
            if(z[p].r==0)return pair(p,0);
            else {
                pair<int,int>px=split(z[p].r,n-z[z[p].l].size-1)
                z[p].r=px.frist;
                int pr=px.second;
                return make_pair(p,pr);
                }
        }
    }
    
     

    query_min:

    查询那些数比x数小,当找到一个根节点比x小时,那么该节点的所有子树都比他小,那么就把子树size+1加到答案里-->删除一个数的时候时用来确定split的k(比要删除的数小的)值

  • 相关阅读:
    node实现将打包后的文件转压缩包
    Git/SVN忽略node_modules文件
    node实现发送邮件
    node搜索文件夹下的指定内容
    node批量修改文件文本内容
    微信小程序上线发布需要做的事情
    两件事 Jquery.form 锁
    .NET MVC 提交表单出现检测到有潜在危险的Request.Form值
    第一次使用TinyMCE
    第一次使用Entity Framework 的CodeFirst
  • 原文地址:https://www.cnblogs.com/sssy/p/7751566.html
Copyright © 2020-2023  润新知