• Splay与FHQ-Treap


    两个一起学的,就放一块了。
    主要是用来存板子。


    Splay

    //This is a Splay Tree.
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int N=1e5+5,INF=0x3f3f3f3f;
    int n,root,cntnode;
    struct node     //始终满足左小右大
    {
        int fa,ch[2],val,siz,cnt;
        //int mark;   //区间反转标记
    }t[N];
    inline bool get(int x) {return t[t[x].fa].ch[1]==x;} //右儿子?1:0
    inline void upd(int x) {t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+t[x].cnt;} //更新计数
    inline void zigzag(int x)   //旋转操作
    {
        int fa=t[x].fa; int gfa=t[fa].fa;
        int d1=get(x),d2=get(fa);
        t[fa].ch[d1]=t[x].ch[d1^1]; t[t[x].ch[d1^1]].fa=fa; //断开fa与x,连接fa与x的儿子
        t[gfa].ch[d2]=x; t[x].fa=gfa;   //断开gfa与fa,连接gfa与x
        t[fa].fa=x; t[x].ch[d1^1]=fa;   //连接x与fa
        upd(fa); upd(x);    //一定是先upd fa再upd x,因为此时fa是x的节点
    }
    void splay(int x,int goal) //伸展操作,即将一个节点x不断旋转至goal的儿子的位置
    {
        while(t[x].fa!=goal)
        {
            int fa=t[x].fa; int gfa=t[fa].fa;
            int d1=get(x),d2=get(fa);
            if(gfa!=goal)
            {
                if(d1==d2) zigzag(fa);  //双旋操作——如果x与fa处在同一方向,要先旋转fa
                else zigzag(x);
            }
            zigzag(x);
        }
        if(goal==0) root=x; //这里用goal=0来实现把x变为根节点的操作
    }
    //以上为维持splayTree功能的基本操作,以下将实现splay的几种常见用途
    void insert(int val) //插入值功能
    {
        int node=root,fa=0;
        while(node && t[node].val!=val)
            fa=node,node=t[node].ch[t[node].val<val]; //通过不断遍历树来找到插入位置
        if(node) t[node].cnt++; //已有此编号
        else
        {
            node=++cntnode; if(fa) t[fa].ch[t[fa].val<val]=node;
            t[node].fa=fa; t[node].val=val; t[node].cnt=t[node].siz=1;
        }
        splay(node,0);
    }
    int kth(int k)  //第k小的数
    {
        int node=root;
        for(;;)
        {
            int son=t[node].ch[0];
            if(k<=t[son].siz) node=son;
            else if(k>t[son].siz+t[node].cnt)
                k-=t[son].siz+t[node].cnt,
                node=t[node].ch[1];
            else return t[node].val;
        }
    }
    int find(int val)   //查找值
    {
        int node=root;
        while(t[node].val!=val && t[node].ch[t[node].val<val])
            node=t[node].ch[t[node].val<val];
        return node;
    }
    int getrk(int val)
    {
        splay(find(val),0);
        return t[t[root].ch[0]].siz;
    }
    int presuc(int val,int tp)  //查找前驱后继,tp=0为前驱,tp=1为后继
    {
        splay(find(val),0); int node=root;
        if(t[node].val<val&&!tp || t[node].val>val&&tp)  //如果找到的节点满足要求就直接返回
            return node;
        node=t[node].ch[tp];
        while(t[node].ch[tp^1])
            node=t[node].ch[tp^1];  //否则找节点左/右子树中最靠右/左的节点(根据平衡树的性质
        return node;
    }
    void delet(int val)
    {
        int pre=presuc(val,0),suc=presuc(val,1);
        splay(pre,0); splay(suc,pre);   //将pre旋转到根,suc旋转到pre的下面,那么suc的左子树就是要删除的
        if(t[t[suc].ch[0]].cnt>1)
        {
            t[t[suc].ch[0]].cnt--;  //常规的删除
            splay(t[suc].ch[0],0);
        }
        else t[suc].ch[0]=0;
    }
    int main()
    {
        insert(-INF); insert(INF);
        scanf("%d",&n);
        for(int i=1,opt,x;i<=n;++i)
        {
            scanf("%d%d",&opt,&x);
            if(opt==1) insert(x);
            if(opt==2) delet(x);
            if(opt==3) printf("%d
    ",getrk(x));
            if(opt==4) printf("%d
    ",kth(x+1));
            if(opt==5) printf("%d
    ",t[presuc(x,0)].val);
            if(opt==6) printf("%d
    ",t[presuc(x,1)].val);
        }
        return 0;
    }
    

    FHQ-Treap

    #include <cstdio>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N=100010;
    int tot,root;
    struct FHQtreap
    {
        int ch[2],val,pri,siz;
        #define l(x) t[x].ch[0]
        #define r(x) t[x].ch[1]
    }t[N];
    
    inline void upd(int x) {t[x].siz=t[l(x)].siz+t[r(x)].siz+1;}
    inline int newNode(int x) 
    {
        t[++tot].siz=1,t[tot].val=x,t[tot].pri=rand();
        return tot;
    }
    
    int merge(int x,int y)
    {
        if(!x||!y) return x|y;
        if(t[x].pri<t[y].pri) return r(x)=merge(r(x),y),upd(x),x;
        else return l(y)=merge(x,l(y)),upd(y),y;
    }
    
    void split(int now,int k,int &x,int &y)
    {
        if(!now) {x=y=0; return;}
        if(t[now].val<=k) x=now,split(r(now),k,r(now),y);
        else y=now,split(l(now),k,x,l(now));
        upd(now);
    }
    
    int kth(int now,int k)
    {
        while(1)
            if(k<=t[l(now)].siz) now=l(now);
            else
            {
                if(k==t[l(now)].siz+1) return now;
                else k-=t[l(now)].siz+1,now=r(now);
            }
    }
    
    int main()
    {
        srand(19260817);
        int T; scanf("%d",&T);
        while(T--)
        {
            int opt,a,x,y,z;
            scanf("%d%d",&opt,&a);
            if(opt==1)
            {
                split(root,a,x,y);
                root=merge(merge(x,newNode(a)),y);
            }
            if(opt==2)
            {
                split(root,a,x,z);
                split(x,a-1,x,y);
                y=merge(l(y),r(y));
                root=merge(merge(x,y),z);
            }
            if(opt==3)
            {
                split(root,a-1,x,y);
                printf("%d
    ",t[x].siz+1);
                root=merge(x,y);
            }
            if(opt==4) printf("%d
    ",t[kth(root,a)].val);
            if(opt==5)
            {
                split(root,a-1,x,y);
                printf("%d
    ",t[kth(x,t[x].siz)].val);
                root=merge(x,y);
            }
            if(opt==6)
            {
                split(root,a,x,y);
                printf("%d
    ",t[kth(y,1)].val);
                root=merge(x,y);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    java内存区域模型
    Java类加载器(双亲委派模型)(综述)
    2.无重复字符的最长子串
    浅谈Java中的对象和引用
    OSI七层协议大白话解读
    MPLS
    计算机网络为什么要分为五层结构?其依据是什么?
    前端技巧小结
    移动端尺寸新写法-rem
    编写高质量代码:Web前端开发修炼之道(四)
  • 原文地址:https://www.cnblogs.com/wzzyr24/p/11965938.html
Copyright © 2020-2023  润新知