• splay学习报告


    省选将至,慌得一批,hale赶紧去学了学splay,防止被打爆,虽说一定会被打爆的

    不过这玩意是真的恶心,hale花了三个中午去搞掉他

    一点点自己的理解啦,嘤嘤嘤

    emmm,废话少说进入正题

    一 。啥是平衡树?

    根据百度百科上面说的:

         平衡树,即平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

    嗯,说得很好,我也知道他很好啊,哼唧唧、

    二。平衡树可以干什么?

      通过不断调整自身平衡来不使自身退化成链,以便于操作,比如查询前驱后继,插入一个数,删除一个数,查询排名为k的数

    先解释一下变量名

    struct node
    {
        int ch[2];//左右儿子
        int son;//儿子的总数便于查询排名
        int cnt;//当前值的个数
        int val;//当前节点的值
        int ff;//保存父亲 
    } t[N];

    操作集合如下

    1。push_up操作,

    其实我也不知道给他取什么名字了,比较线段树的同名操作也就不难理解了

    void push_up(int u)
    {
        t[u].son=t[t[u].ch[0]].son+t[t[u].ch[1]].son+t[u].cnt;
    }

    2。左右旋转操作,这里的话可以参见别人的博克去理解哦 主要是我真的讲不好这个东西  

    但是我这个旋转码量小,可以作为参考而且也挺快的

    void rotate(int x)
    {
        int y=t[x].ff;//当前x的父亲 
        int z=t[y].ff;//当前x的爷爷 
        int k=t[y].ch[1]==x;
        t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;
        t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y;
        t[x].ch[k^1]=y;t[y].ff=x;//一系列的连边操作 
        push_up(y);push_up(x);//向上维护信息 
    }
    void splay(int x,int goal)//当前点,目标点 
    {
        while (t[x].ff!=goal)//还未到达目标点 
        {
            int y=t[x].ff;
            int z=t[y].ff;//同上面的rotate 
            if (z!=goal) (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);//判断是否在一条链上 
            rotate(x);
        }
        if (goal==0) root=x;
    }

    三。插入一个数

    void insert(int x)//插入一个x的数 
    {
        int u=root,ff=0;//用来记录父亲 
        while (u&&t[u].val!=x)
        {
            ff=u;
            u=t[u].ch[x>t[u].val];//很妙的操作,自己想想,也就不难明白为什么的用ch[2]来定义左右儿子了 
        }
        if (u) t[u].cnt++;//如果存在就直接记录个数 
        else//不然就重新开点 
        {
            u=++tot;
            if (ff) t[ff].ch[x>t[ff].val]=u;
            t[u].ch[1]=0;t[u].ch[0]=0;
            t[u].val=x;t[u].ff=ff;
            t[u].cnt=1;t[u].son=1;//开点的一些基本操作 
        }
      splay(u,0);//将点旋上去,保持树的平衡 
    }

    四。查找一个数

    void find(int x)
    {
        int u=root;
        if (!u) return;//这个数不存在,直接退出 
        while (t[u].ch[x>t[u].val]&&x!=t[u].val) 
        u=t[u].ch[x>t[u].val];//不断向下查询位置 
        splay(u,0);//将这个点旋上来 
    }

    五。查询前驱后驱

    int Next(int x,int f)
    { 
       find(x);int u=root;//找到查询的点旋上来 
       if ((t[u].val>x&&f)||(t[u].val<x&&!f)) return u;//如果找到了,返回位置 
       u=t[u].ch[f];
       while (t[u].ch[f^1]) u=t[u].ch[f^1];//不断向下查找 
       return u;
    }

    六。删除一个数

    void Delete(int x)
    {
        int last=Next(x,0);//查询这个数的前驱 
        int next=Next(x,1);//查询这个数的后继 以确定位置 
        splay(last,0);splay(next,last);//旋上去 
        int del=t[next].ch[0];//找到删的这个点 
        if (t[del].cnt>1)//若大于一,则个数减一 
        {
            t[del].cnt--;
            splay(del,0);
        }
        else t[next].ch[0]=0;//不然直接断掉 
    }

    七。查询第k小数

    int K_th(int x)
    {
        int u=root;
        if (t[u].son<x) return false;//找不到不存在,直接输出false 
        while (522520)
        {
            int y=t[u].ch[0];
            if (x>t[y].son+t[u].cnt)//左儿子大于x证明要去右区间去查询 
            {
                x-=t[y].son+t[u].cnt;
                u=t[u].ch[1];
            }
            else if (t[y].son>=x) u=y;//不然在当前区间查询 
            else return t[u].val;//否则就找到啦 
        }
    }

    好了,区间翻转的坑回头再填了,会很快的,最近作业太多了

    hale要加油了,接下来放出代码

    #include<bits/stdc++.h>
    using namespace std;
    int m,n,k,p,root,cnt,tot,opt;
    const int N=2e6+6;
    struct node
    {
        int ch[2],son,cnt,val,ff;
    } t[N];
    void push_up(int u)
    {
        t[u].son=t[t[u].ch[0]].son+t[t[u].ch[1]].son+t[u].cnt;
    }
    void rotate(int x)
    {
        int y=t[x].ff; 
        int z=t[y].ff; 
        int k=t[y].ch[1]==x;
        t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;
        t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y;
        t[x].ch[k^1]=y;t[y].ff=x; 
        push_up(y);push_up(x); 
    }
    void splay(int x,int goal) 
    {
        while (t[x].ff!=goal) 
        {
            int y=t[x].ff;
            int z=t[y].ff;  
            if (z!=goal) (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y); 
            rotate(x);
        }
        if (goal==0) root=x;
    }
    void insert(int x) 
    {
        int u=root,ff=0; 
        while (u&&t[u].val!=x)
        {
            ff=u;
            u=t[u].ch[x>t[u].val]; 
        }
        if (u) t[u].cnt++; 
        else 
        {
            u=++tot;
            if (ff) t[ff].ch[x>t[ff].val]=u;
            t[u].ch[1]=0;t[u].ch[0]=0;
            t[u].val=x;t[u].ff=ff;
            t[u].cnt=1;t[u].son=1; 
        }
      splay(u,0); 
    }
    void find(int x)
    {
        int u=root;
        if (!u) return; 
        while (t[u].ch[x>t[u].val]&&x!=t[u].val) 
        u=t[u].ch[x>t[u].val]; 
        splay(u,0); 
    }
    int Next(int x,int f)
    { 
       find(x);int u=root; 
       if ((t[u].val>x&&f)||(t[u].val<x&&!f)) return u; 
       u=t[u].ch[f];
       while (t[u].ch[f^1]) u=t[u].ch[f^1]; 
       return u;
    }
    void Delete(int x)
    {
        int last=Next(x,0); 
        int next=Next(x,1); 
        splay(last,0);splay(next,last); 
        int del=t[next].ch[0]; 
        if (t[del].cnt>1) 
        {
            t[del].cnt--;
            splay(del,0);
        }
        else t[next].ch[0]=0; 
    }
    int K_th(int x)
    {
        int u=root;
        if (t[u].son<x) return false; 
        while (23333)
        {
            int y=t[u].ch[0];
            if (x>t[y].son+t[u].cnt) 
            {
                x-=t[y].son+t[u].cnt;
                u=t[u].ch[1];
            }
            else if (t[y].son>=x) u=y; 
            else return t[u].val; 
        }
    }
    int main()
    { insert(-2146483647);
      insert(+2146483647);
      scanf("%d",&n);
      for (int i=1;i<=n;i++)
      { int x;scanf("%d%d",&opt,&x);
        if (opt==1) {insert(x);}
        if (opt==2) {Delete(x);}
        if (opt==3) {find(x);printf("%d
    ",t[t[root].ch[0]].son);}
        if (opt==4) {printf("%d
    ",K_th(x+1));}
        if (opt==5) {printf("%d
    ",t[Next(x,0)].val);}
        if (opt==6) {printf("%d
    ",t[Next(x,1)].val);}
      }
      return 0;
    }
    慢即是快,细则是能,于小处铸迤逦
  • 相关阅读:
    深入浅出单实例Singleton设计模式
    设计模式之监听器模式
    Android 驱动(二) IIC简单介绍
    用XCA(X Certificate and key management)可视化程序管理SSL 证书(3)--创建自己定义的凭证管理中心(Certificate Authority)
    编译android-4.3.1_r源代码并刷到自己的Galaxy Nexus I9250真机上
    C++中的单例模式
    MessageDigest简单介绍
    白话经典算法系列之中的一个 冒泡排序的三种实现
    KNN算法理解
    TCP/IP数据包结构具体解释
  • 原文地址:https://www.cnblogs.com/Hale522520/p/10519826.html
Copyright © 2020-2023  润新知