pks大佬的blog

二叉查找树

任何一个节点左子树的所有元素都小于这个节点,右子树的所有元素都大于这个节点

查找一个节点:从根节点开始,比他小就向左走,比他大就向右走

平衡树:解决二叉查找树的一些痛点。

二叉查找树的问题:它的形态并不固定,查找非常依赖于深度

通过一种叫做伸展的操作,让树的深度不那么深

那么什么是伸展?

伸展操作基于一个元操作:旋转(rotate)

如果一个节点之前被访问过,那么之后访问到它的几率会变大

通过旋转把这个点移到根,使下一次访问到它只需要o(1)的时间

Splay操作:把一个点旋转到根或者旋转到某个点下面

有x,y,z三个点,z是y的父亲,y是x的父亲

x,y,z三个点,如果在一条直线上就先转y再转x(让树的深度-1)

如果不在一条直线上,就转两次x

fa记录每一个点的父亲,ch记录节点的两个儿子(有可能没有)

函数:son(x)表示x是它父亲的左儿子还是右儿子

Rotate旋转(其实可以说抬升)

Splay将x的节点转到i的位置上

Cnt表示当前节点的数出现了多少次

Data表示当前节点的数是什么

Size表示当前节点及其子树中共有多少个数
pushup:左节点size+右节点size加上自己的cnt

插入:将x插入到rt节点中

如果x<data[rt],就往左子树插

如果x>data[rt],往右子树插

如果x=data[rt],就cnt[rt]++,size[rt]++,直接return掉

如果rt=0,也就是说这个位置没有出现过,就新建一个位置,rt=++nn(总的节点数),data[rt]=x,size[rt]=cnt[rt]=1,return掉

找前驱(小于x最大的数)和后继(大于x最小的数)

Getpre 按照子节点大小关系往两边找前驱

Getaux 同上,找后继

Getmn 找一颗子树中的最小值 只需要不停往左子树跳就可以了

Delete 删除节点

先找这个点

如果在左边,就往左边删除,如果在右边就往右边删除

如果找到了这个点,分情况。如果不只一个数,就cnt[rt]--,size[rt]--就可以了

否则,先把rt转到根,在右子树找最小的元素

如果没有右子树就让根变成他的左儿子

否则就让右儿子最小的节点转到根,因为最小的节点一定没有左儿子

Getk 查询x的排名

现在树中查找这个节点

找到之后,把他转到根,看他左子树有多少个数,+1就是3的排名0

Getkth 找到第k个数

如果左儿子的size+1<=k并且左儿子的size加上当前节点的数>k,就意味着第k个数一定是这个节点

如果k<左儿子的size+1,就往左节点找

否则就往右儿子找。注意要把左儿子的size和自己的cnt减去

int fa[N],ch[N][];
int cnt[N];
int data[N];
int siz[N]; int son(int x)
{
return x==ch[fa[x]][];
} void pushup(int rt)
{
siz[rt]=siz[ch[rt][]]+siz[ch[rt][]]+cnt[rt];
} void rotate(int x){
int y=fa[x],z=fa[y],b=son(x),c=son(y),a=ch[x][!b];
if(z) ch[z][c]=x; else root=x; fa[x]=z;
if(a) fa[a]=y; ch[y][b]=a;
ch[x][!b]=y;fa[y]=x;
pushup(y);pushup(x);
} void splay(int x,int i){
while(fa[x]!=i){
int y=fa[x],z=fa[y];
if(z==i){
rotate(x);
}else{
if(son(x)==son(y)){
rotate(y);rotate(x);
}else{
rotate(x);rotate(x);
}
}
}
} void insert(int &rt,int x){
if(rt==){
rt=++nn;
data[rt]=x;
siz[rt]=cnt[rt]=;
return;
}
if(x==data[rt]){
cnt[rt]++;
siz[rt]++;
return;
}
if(x<data[rt]){
insert(ch[rt][],x);
fa[ch[rt][]]=rt;
pushup(rt);
}else{
insert(ch[rt][],x);
fa[ch[rt][]]=rt;
pushup(rt);
}
} int getpre(int rt,int x){
int p=rt,ans;
while(p){
if(x<=data[p]){
p=ch[p][];
}else{
ans=p;
p=ch[p][];
}
}
return ans;
} int getsuc(int rt,int x){
int p=rt,ans;
while(p){
if(x>=data[p]){
p=ch[p][];
}else{
ans=p;
p=ch[p][];
}
}
return ans;
} int getmn(int rt){
int p=rt,ans=-;
while(p){
ans=p;
p=ch[p][];
}
return ans;
} void del(int rt,int x){
if(data[rt]==x){
if(cnt[rt]>){
cnt[rt]--;
siz[rt]--;
}else{
splay(rt,);
int p=getmn(ch[rt][]);
if(p==-){
root=ch[rt][];
fa[ch[rt][]]=;
}else{
splay(p,rt);
root=p;fa[p]=;
ch[p][]=ch[rt][];fa[ch[rt][]]=p;
pushup(p);
}
}
return;
}
if(x<data[rt]){
del(ch[rt][],x);
}else{
del(ch[rt][],x);
}
pushup(rt);
} int getk(int rt,int k){
if(data[rt]==k){
splay(rt,);
if(ch[rt][]==){
return ;
}else{
return siz[ch[rt][]]+;
}
}
if(k<data[rt]) return getk(ch[rt][],k);
if(data[rt]<k) return getk(ch[rt][],k);
} int getkth(int rt,int k){
int l=ch[rt][];
if(siz[l]+<=k&&k<=siz[l]+cnt[rt]) return data[rt];
if(k<siz[l]+) return getkth(l,k);
else return getkth(ch[rt][],k-siz[l]-cnt[rt]);
}

qbzt day3 晚上 平衡树的一些思想的更多相关文章

  1. QBZT Day3(zhx ak IOI)

    动态规划 DP和前几天学的东西不大一样,动态规划和数据结构相比是一个非常抽象的东西 先来看看斐波那契数列 定义是F0=0,F1=1,Fn=F(n-1)+F(n-2) 0,1,1,2,3,5,8,13, ...

  2. qbzt day3 下午(好难)

    内容提要 有关数据结构的例题 求逆序对数 统计每个数前面有多少比他大的数 开数组表示这个数之前0~9这些数出现了几次 动态将某个点加一,动态求前缀和 用树状数组 如果数太大了怎么办? 离散化 步骤:先 ...

  3. qbzt day3 上午

    内容提要 堆 lca(最近公共祖先) st表 hash 并查集 树状数组 线段树 数据结构 1.堆 Priority_queue 他滋兹:插入删除查询最大值(最小值) 分为大根堆小根堆 2.LCA 首 ...

  4. qbzt day2 晚上(竟然还有晚上)

    内容提要 搜索 拓展欧几里得 逆元 先是搜索 A* 有几个数组 g 当前点到根节点的深度 h 当前点到终点理想的最优情况需要走几步 f  f=g+h A*就是把所有的f从小到大排序 启发式搜索相较于其 ...

  5. 在平衡树的海洋中畅游(四)——FHQ Treap

    Preface 关于那些比较基础的平衡树我想我之前已经介绍的已经挺多了. 但是像Treap,Splay这样的旋转平衡树码亮太大,而像替罪羊树这样的重量平衡树却没有什么实际意义. 然而类似于SBT,AV ...

  6. BZOJ3682 Phorni 后缀平衡树

    后缀平衡树的裸题 后缀平衡树简单的思想如下 具体的可以去看$clj$的论文 假设我们已经有了串$S$的后缀平衡树 插入一个字母$c$ 我们用$Si$代表原串$S$从第$i$个字符开始的后缀 则后缀$c ...

  7. thusc2016游记&&滚粗记&&酱油记

    #include <cstdio> using namespace std; int main(){ puts("转载请注明出处:http://www.cnblogs.com/w ...

  8. POJ1743 Musical Theme

    Description A musical melody is represented as a sequence of N (1<=N<=20000)notes that are int ...

  9. PKUWC 2018游记

    PKUWC 2018游记 标签: Day\([-inf,0)\) 停课之后一直各种浪的飞起,考试rank20+,不搞颓但是学习很没有状态.还经常带着耳机被谢总抓了好几次,然后被拉过去谈话了好几次... ...

随机推荐

  1. NOIP提高组初赛难题总结

    NOIP提高组初赛难题总结 注:笔者开始写本文章时noip初赛新题型还未公布,故会含有一些比较老的内容,敬请谅解. 约定: 若无特殊说明,本文中未知数均为整数 [表达式] 表示:在表达式成立时它的值为 ...

  2. A-问题收益率

    问题: 在金融中,我们有时会用内部收益率IRR来评价项目的投资财务效益,它等于使得投资净现值NPV等于0的贴现率.换句话说,给定项目的期数T.初始现金流CF0和项目各期的现金流CF1, CF2, …, ...

  3. PY个快速模

    既然这道题是数学题,那就用 PY 吧! 学点东西: print 可以和 c++ 中的 printf 一样快乐的输出格式 另外一点: 这道题可能数据不够强?想想应该有一个 \(0^0 ~\%~ k =0 ...

  4. TScreen研究(有待研究)

    先扔在这里,待研究: http://blog.csdn.net/lailai186/article/details/8141170 procedure TForm1.Button1Click(Send ...

  5. 22 道高频 JavaScript 手写面试题及答案

    实现防抖函数(debounce) 防抖函数原理:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时. 那么与节流函数的区别直接看这个动画实现即可. 手写简化版: // 防抖函数 cons ...

  6. DRF之Jwt 实现自定义和DRF小组件及django-filter插件的使用

    一.DRF之Jwt 实现自定义 二.DRF(过滤,排序,分页)组件 三.Django-filter插件的使用和自定义 """ 1.drf-jwt手动签发与校验 :只是做t ...

  7. 雷电模拟器 v3.71绿色版

    目录 1. 按 2. 介绍 3. 下载地址 1. 按 安卓模拟器目前的市场基本上稳定了,逍遥.夜神.雷电,用的人都很多,网易mumu从阴阳师时代就被大家熟知,腾讯手游助手也是随着吃鸡游戏而火,这两个模 ...

  8. fpga延时程序编写

    //工匠小建 延时计数 100微妙计数 50M*0.00001-1 (个人理解:1s中50M次动作.那么100us多少次动作.做完这些动作就是延时)parameter delay_100us=16'd ...

  9. pypi源

    清华大学pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple豆瓣pip install requests -i https: ...

  10. CentOS搭建NodeJs服务器—Mongodb安装

    1.下载Mongodb 直接下载(下载很慢) cd /mongdb wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-amazon- ...