Spaly基础和应用

一,原理简述

  • 保证每一次操作复杂度 O ( l o g   n ) O(log~n) O(log n) 的做法是把当前操作对象旋转到树根
  • BST 性质(拓展一下就是顺序的特殊性可以维护)

BST是这样的一棵二叉树:对于任意节点,有:

  • 它的值不小于它左子树任意节点的值
  • 它的值不大于它右子树任意节点的值

这个性质就是BST性质,满足这个性质的二叉树就是一棵BST。

BST的中序遍历序列是一个非严格单调递增的序列。

二,注意点

1,唯一的up在spin里
2,get_v_byk 注意特别关注,在加入cnt之后非常不一般
3,up中的子树附加值是cnt
4,splay操作逻辑结果位运算注意括号
5,注意pain操作的不同操作位置,举个例子,倒数第2个操作一但和最后一步写反,就会tle
6,注意splay的位置
7,plug计数由1开始,++idx(不是idx++
8,plug时无根直接返回,就是tr[p]怎样的那个
9,codeblocks括号匹配魔性,不要顺着感觉打括号,要思考打出括号的最佳方案
10,考虑使用宏解决除plug位运算外的部分码量(后期熟了就好了可能)

步骤拆析

1,splay基本元

  • 注意init初始化,子树大小,计数位置都不能是0
  • 一般插入哨兵 2个,INF 和 —INF
  • 子树编号: 0为左子树,1为右子树
struct node
{
    int s[2];
    int v,p,siz,cnt;
    void init(int _p,int _v)
    {
        p= _p;
        v= _v;
        siz= 1;
        cnt= 1;
    }
}tr[N];

2,up 向上更新操作

由题目的具体要求决定

在保序BST 中:

void up(int p)
{
    tr[p].siz= tr[tr[p].s[1]].siz+ tr[tr[p].s[0]].siz +tr[p].cnt;
}

在文艺平衡树中需要翻转标记:

3,spin/rotain(左右旋兼容)

在这里插入图片描述

  • 思考角度:
    (右/左)旋: 拉着 x − y x - y xy 这条链子向(右/左)扯 ,可能把它拽下来或者拖上去之类,结合实际经验还是很好理解的啊

  • 形式化思考:
    x , y , z x,y,z x,y,z 构成的三层结构,按照树中高度排序, d e p ( z ) < d e p ( y ) < d e p ( x ) dep(z)<dep(y)< dep(x) dep(z)<dep(y)<dep(x)

  • 作用: 把传参 x 向上旋转,同时保证 bst

  • 注意: up的位置(这是唯一的up)

void spin(int x)
{
    int y= tr[x].p;
    int z= tr[y].p;
    int k= tr[y].s[1]==x;
    tr[z].s[tr[z].s[1]==y] =x; tr[x].p= z;
    tr[tr[x].s[k^1]].p= y; tr[y].s[k]= tr[x].s[k^1];
    tr[x].s[k^1]= y; tr[y].p= x;
    up(y); up(x);
}

4,spaly(关键!!!)

type 1, 无折型(直线型)
type 2 ,带折型(曲线型)

在这里插入图片描述

  • 传参意义: 把 x 旋转到 k 下面
  • 小知识: s p i n ( x ) spin (x) spin(x) s p i n ( y ) spin(y) spin(y) 换了顺序也无妨,可是时间复杂度差别很大
void splay(int x,int k)
{
    while (tr[x].p!=k)
    {
        int y= tr[x].p;
        int z= tr[y].p;
        if(z!=k)
        {
            if((tr[y].s[1]==x) ^ (tr[z].s[1]==y))spin(x);
            else spin(y);
        }
        spin(x);
    }
    if(!k)root= x;
}

5, plug (插入)

插入节点编号动态分配, val作为排序关键词,注意保证bst性质

void plug(int val)
{
    int u= root; int p =0;
    while (u && tr[u].v!=val) p=u, u= tr[u].s[val>tr[u].v];
    if(u)tr[u].cnt++;
    else
    {
        u= ++idx;
        if(p)tr[p].s [val> tr[p].v] = u;
        tr[u].init(p,val);
    }
    splay(u,0);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流苏贺风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值