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;
}
慢即是快,细则是能,于小处铸迤逦
原文地址:https://www.cnblogs.com/Hale522520/p/10519826.html