首页 > 其他分享 >学习笔记-平衡树

学习笔记-平衡树

时间:2024-04-28 15:45:33浏览次数:12  
标签:val int rtree 笔记 llt 学习 ls 平衡 now

学习笔记-平衡树

treap

#include<bits/stdc++.h>
#define int long long
using namespace std;
#define ls t[x].ch[0]
#define rs t[x].ch[1]
const int N=114514;
const int inf=2147483647;
int cnt=0,root;
mt19937 rnd(0x7f);
struct treap{
	int ch[2], cnt, size, val, rd;
	//treap不需要记录父指针,rd表示节点的随机值
}t[N];

void up(int x){
	t[x].size = t[t[x].ch[0]].size+t[t[x].ch[1]].size+t[x].cnt;
}

void rotate(int &x, int d){//x代表的是旋转时作为父节点的节点,d代表的是旋转的方向
//d==0时是左儿子旋上来, d==1是右儿子旋上来.
    int son = t[x].ch[d];
    t[x].ch[d] = t[son].ch[d^1];
    t[son].ch[d^1] = x; up(x), up(x=son);//相当于up(son)
}

void insert(int &x, int val){
    if(!x){//找到对应位置就新建节点
        x = ++cnt;
        t[x].cnt = t[x].size = 1;
        t[x].val = val, t[x].rd = rnd();
        return;
    }
    t[x].size++;//因为插入了数,所以在路径上每个节点的size都会加1
    if(t[x].val == val){t[x].cnt++; return;}//找到了直接返回
    int d = t[x].val < val; insert(t[x].ch[d], val);//否则递归查找插入位置
    if(t[x].rd > t[t[x].ch[d]].rd) rotate(x, d);
}

void delet(int &x, int val){
    if(!x) return;//防止越界
    if(t[x].val == val){
        if(t[x].cnt > 1){t[x].cnt--, t[x].size--;return;}//有相同的就直接cnt--
        bool d = t[ls].rd > t[rs].rd;
        if(ls == 0 || rs == 0) x = ls+rs;//只有一个儿子就直接把那个儿子放到这个位置
        else rotate(x, d), delet(x, val);//否则将x旋下去,找一个随机值小的替代,直到回到1,2种情况
    }
    else t[x].size--, delet(t[x].ch[t[x].val<val], val);//递归找到要删除的节点.
}

int rk(int x, int val){
    if(!x) return 0;
    if(t[x].val == val) return t[ls].size+1;//找到了就返回最小的那个
    if(t[x].val > val) return rk(ls, val);//如果查找的数在x的左边,则直接往左边查
    return rk(rs, val)+t[ls].size+t[x].cnt;//否则往右边查,左边的所有数累加进答案
}

int kth(int root, int k){
    int x = root;
    while(1){
        if(k <= t[ls].size) x = ls;
        else if(k > t[ls].size+t[x].cnt)
            k -= t[ls].size+t[x].cnt, x = rs;
		else return t[x].val;
    }
}

int pre(int x, int val){
    if(!x) return -inf;//防止越界,同时-inf无法更新答案,
    if(t[x].val >= val) return pre(ls, val);//如果该节点的权值大于等于要找的权值
    //则不能成为前驱,递归查找左子树(有可能找到前驱)
    return max(pre(rs, val), t[x].val);//找右子树中是否存在前驱
}

int nex(int x, int val){//同上
    if(!x) return inf;
    if(t[x].val <= val) return nex(rs, val);
    return min(nex(ls, val), t[x].val);
}

signed main(){
	#ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
	int m,op,x;
    scanf("%lld",&m);
    while(m--)
    {
        scanf("%lld%lld",&op,&x);
        switch(op)
        {
            case 1:{insert(root,x);break;}
            case 2:{delet(root,x);break;}
            case 3:{printf("%lld\n",rk(root,x));break;}
            case 4:{printf("%lld\n",kth(root,x));break;}
            case 5:{printf("%lld\n",pre(root,x));break;}
            case 6:{printf("%lld\n",nex(root,x));break;}
        }
    }
}

FHQ-treap

#include<bits/stdc++.h>
#define N 210000
#define llt long long
using namespace std;
llt root,m,op,x,tot; 
struct TREAP
{
    #define ls(now) tree[now].son[0]
    #define rs(now) tree[now].son[1]
    #define v(now)  tree[now].node
    #define upd(now)    tree[now].siz=tree[now].cnt+tree[ls(now)].siz+tree[rs(now)].siz
    struct NODE{llt node,son[2],rd,cnt,siz;}tree[N];llt sz;
    llt create(llt value){v(++sz)=value;tree[sz].cnt=tree[sz].siz=1;tree[sz].rd=rand();return sz; }
    void split(llt now,llt num,llt &x,llt &y)
    {
        if(!now) {x=y=0;return;}
        if(v(now)>num)  y=now,split(ls(now),num,x,ls(now));
        if(v(now)<=num) x=now,split(rs(now),num,rs(now),y);
        upd(now);
    }
    void merge(llt &now,llt x,llt y)
    {
        if(x==0)    {now=y;return;}
        if(y==0)    {now=x;return;}
        if(tree[x].rd>tree[y].rd)   merge(rs(x),rs(x),y),upd(now=x);
        else                        merge(ls(y),x,ls(y)),upd(now=y);
    }
    void insert(llt &now,llt nnd)
    {
        llt ltree,rtree,is;
        split(now,nnd-1,ltree,rtree);  
        merge(now,ltree,create(nnd)),merge(now,now,rtree);
    }
    void remove(llt &now,llt num)
    {
        llt ltree,rtree,is;
        split(now,num-1,ltree,rtree);split(rtree,num,is,rtree);
        merge(is,ls(is),rs(is));merge(now,ltree,is);merge(now,now,rtree);
    }
    llt check_rk(llt now,llt num)
    {
        llt ltree,rtree,ans;
        split(now,num-1,ltree,rtree);
        ans=tree[ltree].siz+1;
        merge(now,ltree,rtree);
        return ans;
    }
    llt check_num(llt now,llt rk)
    {
        while(1)
        {
            if(tree[ls(now)].siz>=rk)  now=ls(now);
            else if(tree[ls(now)].siz+tree[now].cnt>=rk)    break;
            else rk-=tree[ls(now)].siz+tree[now].cnt,now=rs(now);
        }
        return v(now);
    }
    llt Pre(llt &now,llt num)
    {
        llt ltree,rtree,is;
        split(now,num-1,ltree,rtree),is=ltree;
        while(rs(is))   is=rs(is);
        merge(now,ltree,rtree);
        return v(is);
    }
    llt Next(llt &now,llt num)
    {
        llt ltree,rtree,is;
        split(now,num,ltree,rtree),is=rtree;
        while(ls(is))   is=ls(is);
        merge(now,ltree,rtree);
        return v(is);
    }
}treap;
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    srand(time(0));
    scanf("%lld",&m);
    while(m--)
    {
        scanf("%lld%lld",&op,&x);
        switch(op)
        {
            case 1:{treap.insert(root,x);break;}
            case 2:{treap.remove(root,x);break;}
            case 3:{printf("%lld\n",treap.check_rk(root,x));break;}
            case 4:{printf("%lld\n",treap.check_num(root,x));break;}
            case 5:{printf("%lld\n",treap.Pre(root,x));break;}
            case 6:{printf("%lld\n",treap.Next(root,x));break;}
        }
    }
    return 0;
}

标签:val,int,rtree,笔记,llt,学习,ls,平衡,now
From: https://www.cnblogs.com/hzoi-wang54321/p/18163861

相关文章

  • DSP学习笔记
    DSP学习笔记之EPWMEPWM模块介绍F28335最多有18路PWM输出,其中有6个ePWM模块由两路ePWM输出组成,分为ePWMxA和ePWMxB,这一对PWM输出,可以配置成两路独立的单边沿PWM输出,或者两路独立的但互相相对称的双边沿PWM输出,或者一对双边沿非对称的PWM输出,因为每对PWM模块中的两个PWM......
  • 算法学习笔记(14):区间最值操作和历史最值问题
    区间最值操作,历史最值问题来源吉老师2016集训队论文,oiwiki,网络上各种博客。概述区间最值操作指的是:将所有的$i\in$\((l,r)\),\(a_i=min或max(a_i,k)\)。历史最值问题指的是:新定义一个数组\(b[]\),\(b[i]=max或min(b[i],a[i])\)。还有一种是历史版本和,即\(......
  • Docker安装笔记
    1、配置yum仓库(系统为Centos7)创建Centos基础镜像仓库,到阿里云镜像站https://developer.aliyun.com/mirror/找到Centos可以找到对应系统的镜像仓库。wget-O/etc/yum.repos.d/CentOS-Base.repohttps://mirrors.aliyun.com/repo/Centos-7.repo2、配置docker仓库创建Docker镜......
  • 无需重新学习,使用 Kibana 查询/可视化 SLS 数据
    作者:荆磊场景现在通过SLS的ES兼容能力,可以很方便地实现用Kibana来查询和可视化SLS的数据。对于从ES迁移到SLS的用户可以继续保留原来的Kibana使用习惯。下面来演示如何通过Kibana来访问SLS。使用方法部署架构这里蓝色部分是需要客户端部署的组件。Kibana......
  • 开源相机管理库Aravis学习——PixelFormat编码规则
    目录前言前置知识PixelFormatBpp编码规则源码分析分类标准补充ARV_PIXEL_FORMAT_BIT_PER_PIXEL参考文章前言在学习Aravis官方例程的时候,有这么一个函数:arv_camera_get_pixel_format,它的返回类型是ArvPixelFormat(本质是个32位无符号整数)。这意味着对于每个图像数据格式,都有自己......
  • Java学习之Jackson
    介绍两种Java主流的转化工具Jackson和FastJson,一般项目中建议只选其中一种。Jackson1.将JSON字符串转成Java对象:readvalue方法第一个参数是Json字符串,第二个参数是将要转化类的类型ObjectMapperobjectMapper=newObjectMapper();MatchMatch=objectMapper.readValue(jsonStr......
  • 开源相机管理库Aravis例程学习(五)——camera-api
    目录简介例程代码函数说明arv_camera_get_regionarv_camera_get_pixel_format_as_stringarv_camera_get_pixel_formatARV_PIXEL_FORMAT_BIT_PER_PIXEL简介本文针对官方例程中的:03-camera-api做简单的讲解。并介绍其中调用的arv_camera_get_region,arv_camera_get_pixel_format_as......
  • AI模型 Llama 3体验笔记
    4月19日Meta重磅推出了最新大型开源人工智能(AI)模型——Llama3,模型分为两种规模:8B和70B参数,旨在让个人、创作者、研究人员和各种规模的企业能够负责任地试验、创新和扩展他们的想法。  已经可以很方便的在本地部署、体验。Linux系统下安装脚本:curl-fsSLhttps://oll......
  • 程序员William的英语学习之旅:从零到流利,我的八年心路历程
    作者:程序员William原文链接先发在CSDN:https://blog.csdn.net/CoderWilliam/article/details/138261612本文如需转载需征得作者本人同意,谢谢。大家好,我是程序员William。作为一名程序员,英语很长时间都是我的软肋。在国内互联网圈里打拼8年,日益感受到英语重要性。无数次翻译软件......
  • APP 移动应用自动化 Appium 2.0 使用笔记(一)
    APP移动应用自动化Appium2.0使用笔记(一)为什么要升级到Appium2.0?最主要的原因就是:自2022年1月1日起,Appium团队不再维护或支持Appium1。所有官方支持的平台驱动程序仅与Appium2兼容。目录安装Appium2.0启动Appium2.0安装注意,你如果已经安装了原Appium1......