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