zoukankan      html  css  js  c++  java
  • FHQ treap学习(复习)笔记

    .....好吧....最后一篇学习笔记的flag它倒了.....

    好吧,这篇笔记也鸽了好久好久了...

    比赛前刷模板,才想着还是补个坑吧...

    FHQ,这个神仙(范浩强大佬),发明了这个神仙的数据结构,

    首先,本篇博客使用洛谷普通平衡树为背景,即

    • 查找前驱
    • 查找后记
    • 查找kth的数
    • 查找k的排名
    • 插入一个数
    • 删除一个数

    FHQ treap,是一个treap,它还是和treap一样,是tree+heap,所以它也有一个键值维护堆的性质。

    它可以干任何treap和Splay能干的事。

    它的实现主要由两个函数实现:

    merge:把两棵树合并成一棵

    split:把树分割成两棵

    在这里介绍两个函数的实现方法:

    merge

     

    可以看到,它把两棵树合并了起来,但是并不是简单地接起来,而是打散,重新组合。

    代码:

    int merge(int x,int y)//把xy为根的两棵子树给合并
    {
        if(!x||!y)//如果一边没了
        return x+y;//就返回
        if(t[x].key<t[y].key)//维护key值,如果x的key值小于y的k值
        {
            t[x].son[1]=merge(t[x].son[1],y);//说明此时一定不符合堆性质,把x的右儿子和y合并
            update(x);//更新相关变量
            return x;//返回根节点
        }
        else
        {
            t[y].son[0]=merge(x,t[y].son[0]);//同上
            update(y);
            return y;
        }
    }
    View Code

    通过这样一个递归,不断拆分节点&&合并的过程中,就建立了一棵新树。

    split:

     

    从上图可得:(把树从5分开)

    split的过程就是把树拆分成左右树,左树所有节点权值都小于k,右树的节点权值都大于k。

    怎么实现呢?

    代码:

    void split(int now,int k,int &x,int &y)//把一棵树now给从k分割成x和y
    {
        if(!now) x=y=0;//如果没有了,就返回
        else
        {
            if(t[now].v<=k) //如果当前点的权值小于k,它应该在左子树
            {
                x=now;//更新
                split(t[now].son[1],k,t[now].son[1],y);分割右儿子,找一个可能的更大的
            }
            else//同上
            {
                y=now;
                split(t[now].son[0],k,x,t[now].son[0]);
            }
            update(now);
        }
    }
    View Code

    这样,我们就可以干以上的事了。

    前置:查找kth

    因为建立的事一个二叉查找树,所以还是可以像遍历二叉查找树那样查找kth的。

    代码十分简单

    int kth(int now,int k)
    {
        while(1)
        {
            if(k<=t[t[now].son[0]].size) 
                now=t[now].son[0];
            else
            {
                if(k==t[t[now].son[0]].size+1)
                return now;
                else 
                {
                    k-=t[t[now].son[0]].size+1;
                    now=t[now].son[1];
                }
            }
        }
    }
    View Code

    然后就可以A掉普通平衡树了。

    插入新节点:首先暴力新建一个节点

    int new_node(int k)
    {
        tot++;
        t[tot].size=1;
        t[tot].v=k;
        t[tot].key=rand();
        return tot;
    }
    View Code

    然后把树从k地方断开,把新节点看做一棵树,把它和上下树合在一起就行了

    split(rt,a,x,y);
    rt=merge(merge(x,new_node(a)),y);
    View Code

    删除节点:

    把树从k断开,然后把左树从k-1断开,然后把上下树给合并,把k节点扔了就行了

    split(rt,a,x,z);
    split(x,a-1,x,y);
    y=merge(t[y].son[0],t[y].son[1]);
    rt=merge(merge(x,y),z);
    View Code

    查找排名:

    把树从k分开,则k所在的数的size即使排名

    split(rt,a-1,x,y);
    printf("%d
    ",t[x].size+1);
    rt=merge(x,y);
    View Code

    查找kth:

    直接用kth函数即可

    printf("%d
    ",t[kth(rt,a)].v);
    View Code

    前驱:

    把树从k分开,则size-1大小的那个kth点就是前驱

    split(rt,a-1,x,y);
    printf("%d
    ",t[kth(x,t[x].size)].v);
    rt=merge(x,y);
    View Code

    后继:同上

    split(rt,a,x,y);
    printf("%d
    ",t[kth(y,1)].v);
    rt=merge(x,y);
    View Code

    完整高清无码代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+10;
    struct tree
    {
        int son[2],v,key,size;
    }t[maxn];
    int tot=0,rt=0;
    void update(int p)
    {
        t[p].size=t[t[p].son[0]].size+t[t[p].son[1]].size+1;
    }
    int new_node(int k)
    {
        tot++;
        t[tot].size=1;
        t[tot].v=k;
        t[tot].key=rand();
        return tot;
    }
    int merge(int x,int y)//o?2¢ò?x£?y?a?ùμ?á???×óê÷
    {
        if(!x||!y)
        return x+y;
        if(t[x].key<t[y].key)
        {
            t[x].son[1]=merge(t[x].son[1],y);
            update(x);
            return x;
        }
        else
        {
            t[y].son[0]=merge(x,t[y].son[0]);
            update(y);
            return y;
        }
    }
    void split(int now,int k,int &x,int &y)//ò?è¨?μk·?à?nowê÷3éx,y 
    {
        if(!now) x=y=0;
        else
        {
            if(t[now].v<=k) //°??ùóDD?óúkμ?è¨?μμ??úμ?·?μ?ò???ê÷?D
            {
                x=now;
                split(t[now].son[1],k,t[now].son[1],y);
            }
            else
            {
                y=now;
                split(t[now].son[0],k,x,t[now].son[0]);
            }
            update(now);
        }
    }
    int kth(int now,int k)
    {
        while(1)
        {
            if(k<=t[t[now].son[0]].size) 
                now=t[now].son[0];
            else
            {
                if(k==t[t[now].son[0]].size+1)
                return now;
                else 
                {
                    k-=t[t[now].son[0]].size+1;
                    now=t[now].son[1];
                }
            }
        }
    }
    int x,y,z,n;
    int main()
    {
        srand((unsigned)time(NULL));
        scanf("%d",&n);
        int flag,a,b,c;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&flag);
            scanf("%d",&a);
            if(flag==1)
            {
                split(rt,a,x,y);
                rt=merge(merge(x,new_node(a)),y);
            }
            if(flag==2)
            {
                split(rt,a,x,z);
                split(x,a-1,x,y);
                y=merge(t[y].son[0],t[y].son[1]);
                rt=merge(merge(x,y),z);
            }
            if(flag==3)
            {
                split(rt,a-1,x,y);
                printf("%d
    ",t[x].size+1);
                rt=merge(x,y);
            }
            if(flag==4)
            {
                printf("%d
    ",t[kth(rt,a)].v);
            }
            if(flag==5)
            {
                split(rt,a-1,x,y);
                printf("%d
    ",t[kth(x,t[x].size)].v);
                rt=merge(x,y);
            }
            if(flag==6)
            {
                split(rt,a,x,y);
                printf("%d
    ",t[kth(y,1)].v);
                rt=merge(x,y);
            }
        }
        return 0;
    }
  • 相关阅读:
    WPF Attached event
    WPF Progressbar
    IDisposable
    CommandTarget属性
    观察者模式
    DesignerSerializationVisibility, Browsable,Category Attribute
    CVS使用手册
    Javascript原型的简单理解
    由插件独特的处理器产生页面
    教训
  • 原文地址:https://www.cnblogs.com/ajmddzp/p/11842270.html
Copyright © 2011-2022 走看看