首页 > 其他分享 >平衡树乱讲

平衡树乱讲

时间:2024-07-30 21:17:48浏览次数:7  
标签:乱讲 val int siz merge ls ans 平衡

平衡树

这里讲 非旋Treap,FHQTreap

概述

FHQTreap 的思想基于分裂和合并

存储的信息是:

\(ls\) 和 \(rs\) 左右儿子。

\(val\) 权值

\(siz\) 子树大小。

对于 Treap 比较独特的是 \(rd\),实际上是一个随机优先级。

对于相同权值的不同的点,不会记录成一个点,故没有记录次数的 \(cnt\)。

函数

push

更新答案,子树大小为左右儿子大小 + 1。

void push(int x){siz[x] = siz[ls[x]]+siz[rs[x]]+1;}

split

分裂,这里按照权值 \(val\) 分裂。

具体地,给定一个 \(v\),要将原本的平衡树 \(T\) 分裂成 \(T_x\) 和 \(T_y\) 两棵。

对于任意 \(i \in T_x\) 和 \(j \in T_y\) 都有 \(val_i < v < val_j\)。

满足平衡的性质。

如果 \(val_p < v\) 那么 \(p\) 应当属于 \(T_x\) 中。那么应该向右递归。

反则向左递归。

类似二分的思想,通过左右递归,等效于二分中的 \(mid = r\) 或 \(mid = l\)。

递归边界:\(p=0\) 也就是找到最终的位置了。

    void split(int p,int v,int &x,int &y){
        if(!p) {
            x=y=0;
            return ;
        }if(val[p] <= v) split(rs[p],v,rs[x=p],y);
        else split(ls[p],v,x,ls[y=p]);
        push(p);
    }

merge

合并,是对于 split 相反的一种操作。

对于两棵平衡树 \(T_x\) 和 \(T_y\) 要将他们合并。

对于任意 \(i \in T_x\) 和 \(j \in T_y\):

根据定义,都有 \(val_i < val_j\)。

在此,要生成随机数,也就是 \(rd\)。

如果 \(rd_x > rd_y\) 那么前者优先级更高,也就是 \(x\) 作为 \(y\) 的父节点。

再对于 \(val\) 进行比较,判断其属于左儿子还是右儿子。

例:如果 \(val_x < val_y\) 那么 \(y\) 是 \(x\) 的右儿子。

直接调用 \(merge(rs_x,y)\) 即可。

小于同理。

如果 \(x\) 和 \(y\) 有一个为空,

那么返回他们其中一个,直接 \(x \ or \ y\) 即可。

int merge(int x,int y){
        if(!x||!y)return x|y;
        if(rd[x]<rd[y]){
            ls[y]=merge(x,ls[y]),push(y);
            return y;
        }
        rs[x]=merge(rs[x],y),push(x);
        return x;
    }

new node

新建节点。

int nd(int v){
        int x=++node;
        val[x]=v;
        rd[x]=rand();
        siz[x]=1;
        return x;
    }

insert

插入。

插入一个 \(v\),先将 \(val_i < v\) 的 \(i\) 分到 \(T_x\) 中。

反之分到 \(T_y\) 中。

再重新设定 root 即可。

void insert(int v){
        int x=0,y=0;
        split(R,v-1,x,y);
        R=merge(merge(x,nd(v)),y);
    }

del

删除。

删除一个 \(v\)。首先按照 \(v\) 把 \(T\) 分裂成 \(T_x\) 和 \(T_z\)。

再按照 \(v-1\) 把 \(T_x\) 分成 \(T_x\) 和 \(T_y\)。

因此此时 \(T_y\) 的权值都是 \(v\)。

但是只能删除一个。

所以直接删除 \(T_y\) 的根。

把它的左右子树合并起来。

再与 \(T_x\) 和 \(T_z\) 合并起来即可。

void del(int v){
        int x=0,y=0,z=0;
        split(R,v,x,z),split(x,v-1,x,y);
        R=merge(merge(x,y=merge(ls[y],rs[y])),z);
    }

kth

第 k 大。

当前遍历到 \(p\)。

若 \(k \le siz_ls_p\)。递归左儿子。

若 \(k=sz_ls_p + 1\),返回 \(val_p\)。

否则,递归右儿子。

int kth(int k){
        int p=R;
        while(true){
            if(k<=siz[ls[p]])p=ls[p];
            else if(k==siz[ls[p]]+1)return val[p];
            else k-=siz[ls[p]]+1,p=rs[p];
        }
    }

pre

前驱。

先用 \(v-1\) 分裂成 \(T_x\) 和 \(T_y\)。

所以找到 \(T_x\) 中的最大值即可。

int pre(int v){
        int p=R,ans=0;
        while(true){
            if(!p) return ans;
            else if(v<=val[p])p=ls[p];
            else ans=val[p],p=rs[p];
        }
    }

sec

后继。

同理前驱。

int suc(int v){
        int p=R,ans=0;
        while(true){
            if(!p) return ans;
            else if(v>=val[p])p=rs[p];
            else ans=val[p],p=ls[p];
        }
    }

rank

排名。

查询 \(v\) 排名。

按 \(v-1\) 分裂。

分裂成 \(T_x\) 和 \(T_y\)。

答案为 \(siz_x + 1\)。

最后再合并。


int rnk(int v){
        int x=0,y=0,ans=0;
        split(R,v-1,x,y);ans=siz[x]+1;
        return R=merge(x,y),ans;
    }

Code

namespace FHQTreap{
    int R,node,ls[N],rs[N],val[N],rd[N],siz[N];
    void push(int x){siz[x] = siz[ls[x]]+siz[rs[x]]+1;}
    void split(int p,int v,int &x,int &y){
        if(!p) {
            x=y=0;
            return ;
        }if(val[p] <= v) split(rs[p],v,rs[x=p],y);
        else split(ls[p],v,x,ls[y=p]);
        push(p);
    }int merge(int x,int y){
        if(!x||!y)return x|y;
        if(rd[x]<rd[y]){
            ls[y]=merge(x,ls[y]),push(y);
            return y;
        }
        rs[x]=merge(rs[x],y),push(x);
        return x;
    }int nd(int v){
        int x=++node;
        val[x]=v;
        rd[x]=rand();
        siz[x]=1;
        return x;
    }void insert(int v){
        int x=0,y=0;
        split(R,v-1,x,y);
        R=merge(merge(x,nd(v)),y);
    }void del(int v){
        int x=0,y=0,z=0;
        split(R,v,x,z),split(x,v-1,x,y);
        R=merge(merge(x,y=merge(ls[y],rs[y])),z);
    }int kth(int k){
        int p=R;
        while(true){
            if(k<=siz[ls[p]])p=ls[p];
            else if(k==siz[ls[p]]+1)return val[p];
            else k-=siz[ls[p]]+1,p=rs[p];
        }
    }int pre(int v){
        int p=R,ans=0;
        while(true){
            if(!p) return ans;
            else if(v<=val[p])p=ls[p];
            else ans=val[p],p=rs[p];
        }
    }int suc(int v){
        int p=R,ans=0;
        while(true){
            if(!p) return ans;
            else if(v>=val[p])p=rs[p];
            else ans=val[p],p=ls[p];
        }
    }int rnk(int v){
        int x=0,y=0,ans=0;
        split(R,v-1,x,y);ans=siz[x]+1;
        return R=merge(x,y),ans;
    }
}using namespace FHQTreap;

标签:乱讲,val,int,siz,merge,ls,ans,平衡
From: https://www.cnblogs.com/gsczl71/p/18333359

相关文章

  • 「FHQ-Treap —— 码量最小的平衡树」学习笔记
    不同于普通Treap,FHQ-Treap不需要左旋和右旋操作来处理数据。因此FHQ-Treap也称作无旋Treap。FHQ-Treap是基于Split(分裂)和Merge(合并)两种操作的平衡树。其与普通Treap的原理完全不同。一些基础的操作:例如Insert(插入元素)和Delete(删除元素)。对于Insert(插入元素),新建一......
  • 高维前缀和乱讲
    OI-Wiki看不懂啊,学了一上午。常见的二维前缀和求法多为容斥原理,虽然这样的计算相对直观且便于记忆,但是当维数往上升高时其复杂度会大大提高,对于更高维度的前缀和可以使用“高维前缀和”这一方法,本质上是基于DP的。首先我们可以了解一种一般的优化,我们先对每一“行”求前......
  • 过采样SMOTE逻辑回归、SVM、随机森林、AdaBoost和XGBoost对不平衡数据分析预测
    全文链接:https://tecdat.cn/?p=37115原文出处:拓端数据部落公众号分析师:YimengLi近几年,伴随着互联网的发展,在线食品配送业务成为了新潮流。在此背景下,我们帮助客户对“在线食品交付偏好-班加罗尔地区”数据开展研究,建立印度在线食品配送平台消费者的用户画像,研究影响顾客购买意......
  • 浅谈平衡树
    平衡树,是一种数据结构,可以实现一类元素在线性结构中动态变化,基于二叉搜索树,满足二叉搜索树的所有性质。二叉搜索树(BST)二叉搜索树是一种二叉树形结构,它满足以下性质:空树是二叉搜索树。若二叉搜索树的左子树不为空,则其左子树上所有点的附加权值均小于其根节点的值。若二......
  • 基于完美反射假设的自动白平衡算法
    简介完美反射假设(PerfectReflectorAssumption)是另一种常见的自动白平衡(AWB)方法。它假设图像中有一些物体具有完美反射特性,能够反射所有入射光。这意味着这些物体的反射光应该是白色或灰色,通过识别这些物体并调整图像的色彩平衡,可以实现白平衡。原理完美反射假设的核心思想......
  • 基于平衡优化器算法优化的TSP问题求解
    智能优化算法应用:基于平衡优化器算法的TSP问题求解-附代码文章目录智能优化算法应用:基于平衡优化器算法的TSP问题求解-附代码1.TSP问题3.平衡优化器算法4.实验参数设定5.算法结果6.Matlab代码7.Python代码摘要:TSP是数学领域内一道著名的难题之一,如何求解一直是......
  • 在设计电子产品时,如何平衡抗震和抗振需求以确保产品的整体性能?
            在电子产品的设计中,抗震和抗振需求是两个重要的考量因素,它们虽然在目标上有所重叠,即都是为了确保产品在各种使用环境下的可靠性和稳定性,但它们的侧重点和应对措施有所不同:抗震需求:定义:抗震需求通常指的是电子产品在设计时需要考虑到的抵抗外部冲击和震动的......
  • 如何在 PyTorch 中使用类权重和焦点损失来处理多类分类的不平衡数据集
    我正在研究语言任务的多类分类(4类),并使用BERT模型进行分类任务。我正在关注这篇博文NLP的迁移学习:微调BERT用于文本分类我的BERT微调模型返回nn.LogSoftmax(dim=1)我的数据非常不平衡,所以我使用了|||计算类别的权重并使用损失中的权重。......
  • 如何优雅地写注释:找到代码注释的黄金平衡点
    在软件开发的世界里,注释是代码的伴侣,它们帮助我们记录思路,解释复杂的逻辑,以及为后来者提供指引。然而,注释的艺术在于找到恰当的平衡——既不过于冗余,也不过于吝啬。本文将探讨如何优雅地写出恰到好处的注释。注释有啥用首先,我们需要认识到注释的价值。好的注释可以:提高代码的......
  • 如何平衡 PyTorch 数据集?
    我有一个不平衡的PyTorch数据集。A和V样本的数量远低于其他样本我想平衡我的数据集,即使我必须删除属于主流类的样本。怎么办?现在,如果某些类的数量超过某个固定值,我只需删除某些类的样本。这在技术上比较复杂并且不方便。也许有一些sklearn或PyTorch方法可......