博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
splay学习报告
阅读量:5152 次
发布时间:2019-06-13

本文共 4515 字,大约阅读时间需要 15 分钟。

 

省选将至,慌得一批,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

六。删除一个数

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
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
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
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
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\n",t[t[root].ch[0]].son);} if (opt==4) {printf("%d\n",K_th(x+1));} if (opt==5) {printf("%d\n",t[Next(x,0)].val);} if (opt==6) {printf("%d\n",t[Next(x,1)].val);} } return 0;}

 

转载于:https://www.cnblogs.com/Hale522520/p/10519826.html

你可能感兴趣的文章