首页 > 其他分享 >Splay 平衡树模板

Splay 平衡树模板

时间:2022-09-05 19:34:37浏览次数:72  
标签:ch cur val int Splay fa 平衡 root 模板

OI-wiki写的非常好,所以在这里加以自己的注释理解存一下模板qwq。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i<(b);++i)
#define rrep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
template <typename T>
inline void read(T &x){
    x=0;char ch=getchar();bool f=0;
    while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    if(f)x=-x;
}
template <typename T,typename ...Args>
inline void read(T &tmp,Args &...tmps){read(tmp);read(tmps...);}
const int N = 1e5 + 5;
int root,tot,fa[N],ch[N][2],val[N],cnt[N],siz[N];
struct Splay{
    void maintain(int x){
        siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + cnt[x];
    }//pushup
    bool get(int x){return x == ch[fa[x]][1];}//是爹的左儿子(0)还是右儿子(1)
    void clear(int x){//销毁结点
        ch[x][0] = ch[x][1] = fa[x] = val[x] = siz[x] = cnt[x] = 0;
    }
    void rotate(int x){//旋转操作
        int y = fa[x],z = fa[y],chk = get(x);//爹,爹的爹,是爹的哪个儿子
        ch[y][chk] = ch[x][chk^1];//如果我是爹的左儿子,把我的右儿子给爹的左儿子//如果是右儿子,把我的左儿子给爹的右儿子
        if(ch[x][chk^1])fa[ch[x][chk^1]] = y;//把这个儿子的爹改成我的爹
        ch[x][chk^1] = y;//父子关系换了,哈哈!
        fa[y] = x;fa[x] = z;//哈哈!哈哈!
        if(z)ch[z][y == ch[z][1]] = x;//如果爹的爹存在,更新儿子,你滴儿子是我辣!
        maintain(x);maintain(y);//pushup pushup
    }
    void splay(int x){
        for(int f;f = fa[x];rotate(x))//我还有爹吗,有就旋
        if(fa[f])rotate(get(x) == get(f) ? f : x);//如果有爹,相同的话要先旋爹
        root = x;//我是根辣!
    }
    void ins(int k){
        if(!root){
            val[++tot] = k;
            cnt[tot]++;
            root = tot;
            maintain(root);return;//空就新建结点
        }
        int cur = root,f = 0;
        while(1){
            if(val[cur] == k){//这个数存在那么就cnt+1就好了
                cnt[cur]++;
                maintain(cur);maintain(f);
                splay(cur);//别忘了
                break;
            }
            f = cur;
            cur = ch[cur][val[cur] < k];//当前节点比k小就往右,否则往左
            if(!cur){//走不下去了,就新建节点,完事!
                val[++tot] = k;
                cnt[tot]++;
                fa[tot] = f;
                ch[f][val[f] < k] = tot;//别忘了爹的儿子
                maintain(tot);maintain(f);splay(tot);break;
            }
        }
    }
    int rk(int k){
        int res = 0,cur = root;
        while(1){
            if(k < val[cur])cur = ch[cur][0];//当前节点大了就往左查
            else{
                res += siz[ch[cur][0]];//否则加上左子树的大小,注意不加自己
                if(k == val[cur]){//如果刚好查到了那么就是返回答案了,比他小的个数 + 1
                    splay(cur);
                    return res + 1;
                }       
                res += cnt[cur];//比当前结点大,那么加上当前结点继续右子树
                cur = ch[cur][1];//右子树
            }
        }
    }
    int kth(int k){
        int cur = root;
        while(1){
            if(ch[cur][0] && k <= siz[ch[cur][0]])cur = ch[cur][0];//左儿子够
            else{
                k -= siz[ch[cur][0]] + cnt[cur];//权值线段树啦~~
                if(k <= 0){//够了就是当前结点了
                    splay(cur);return val[cur];
                }
                cur = ch[cur][1];//不够往右跳
            }
        }
    }
    int pre(){
        int cur = ch[root][0];//前驱,就是先插入这个数,把他旋到根,那么就是他左儿子的右儿子最深那个,也就是最大的小于他的
        if(!cur)return cur;//不存在
        while(ch[cur][1])cur = ch[cur][1];//跳最深的右儿子
        splay(cur);//嗯,别忘了!
        return cur;
    }
    int nxt(){
        int cur = ch[root][1];//后继同理
        if(!cur)return cur;
        while(ch[cur][0])cur = ch[cur][0];//不过跳右子树的左儿子
        splay(cur);//咳咳,别忘了!
        return cur;
    }
    void del(int k){
        rk(k);//就是把他的结点扔到根
        if(cnt[root] > 1){//有一堆,删一个就好了
            cnt[root]--;
            maintain(root);
            return;
        }
        if(!ch[root][0] && !ch[root][1]){//这棵树只有他一个
            clear(root);//那么就删掉了
            root = 0;
            return ;
        }
        if(!ch[root][0]){//只有右儿子
            int cur = root;
            root = ch[root][1];//删掉就好了,更新一下右儿子的父亲
            fa[root] = 0;
            clear(cur);
            return;
        }
        if(!ch[root][1]){
            int cur = root;
            root = ch[root][0];//左边同理
            fa[root] = 0;
            clear(cur);
            return;
        }
        int cur = root;//最麻烦的!
        int x = pre();//先找到前驱
        fa[ch[cur][1]] = x;//右儿子挂到前驱下
        ch[x][1] = ch[cur][1];//前驱的右儿子是他的右儿子
        clear(cur);//删了就好了
        maintain(root);
    }
}tree;
signed main(){
    int n,opt,x;
    read(n);
    while(n--){
        read(opt,x);
        if(opt == 1)tree.ins(x);
        else if(opt == 2)tree.del(x);
        else if(opt == 3)printf("%d\n",tree.rk(x));
        else if(opt == 4)printf("%d\n",tree.kth(x));
        else if(opt == 5)tree.ins(x),printf("%d\n",val[tree.pre()]),tree.del(x);
        else tree.ins(x),printf("%d\n",val[tree.nxt()]),tree.del(x);
    }
}

标签:ch,cur,val,int,Splay,fa,平衡,root,模板
From: https://www.cnblogs.com/wsxxs/p/16659271.html

相关文章

  • 今日内容 视图层与模板层
    网页伪静态实际上伪静态是个动态页面,只是通过技术手段伪装成立静态页面的样子,伪静态页面的内容是通过读取数据库生成的。将动态网页伪装成静态网页从而提升网页被搜......
  • 【luogu P5826】【模板】子序列自动机
    【模板】子序列自动机题目链接:luoguP5826题目大意给你一个序列,每次再给你一个序列,问你新的序列是不是一开始的序列的子序列。思路如果字符少不难想象到一个\(f_{i,j......
  • 导出模板设置其中某一列下拉选
    导出模板设置其中某一列下拉选 *设置下拉选 */ for(inti=0;i<headers.length;i++){ Stringheader=headers[i]; if(header.equals("电站简称")){ Str......
  • 拿来即用的下载Excel模板
    模板导出拿来即用 @PostMapping("/templateExport") @ApiOperation(value="模板导出",notes="作者:yysd") publicReturnObjectexportAuditContent(HttpServletRe......
  • Handel 分类中的不平衡数据
    Handel分类中的不平衡数据预测我想知道的他们中的大多数人没有可预测的信息。例如预测欺诈的发生,感染预后或简而言之“因为东西少所以我想知道更多。”在这项工作中......
  • MLops:我最喜欢的数据科学项目的 Github 项目模板
    MLops:我最喜欢的数据科学项目的Github项目模板source:unsplash.com-@yancyminTLDR:在这个故事中,我将分享一个git项目结构,我经常将其用作数据科学项目的起点,并......
  • 【2022.9.2】Django框架(网页伪静态、视图层、模板层)
    学习内容概要网页伪静态视图层三板斧JsonResponseform表单上传文件FBV与CBV(核心)CBV源代码(面向对象)模板层模板语法传值模板语法之过滤器模板语法之标签......
  • SPFA例题/模板
    https://www.acwing.com/problem/content/1131/ #include<bits/stdc++.h>#definefore(x,y,z)for(LLx=(y);x<=(z);x++)#defineforn(x,y,z)for(LLx=(y);x<(z);......
  • 算法模板
    基础算法倍增intget(intl,intr){intd=r-l+1;intc=upper_bound(one,one+max_v+1,d)-one-1;returnmax(dp[l][c],dp[r-one[c]......
  • django4/网页伪静态/视图层/模板层
    网页伪静态动态页动态网页,页面代码虽然没有变,但是显示的内容却是可以随着时间、环境或者数据库操作的结果而发生改变的。静态页即静态网页,是实际存在的,无需经过服务器......