首页 > 编程语言 >AcWing 算法提高课 treap平衡树

AcWing 算法提高课 treap平衡树

时间:2022-09-28 20:15:20浏览次数:62  
标签:return val int tr else treap 算法 key AcWing

1、基本性质

tree+heap=treap

平衡树包含treap 红黑树 splay sbt AVL等等

splay比较常用

treap=

①BST 二叉搜索树

+

②heap

2、set不能做的操作

 

 ⑤和⑥这种与排名相关的操作比较困难

3、treap的实现

思想:让二叉搜索树尽量变得随机(以大根堆为例)

 

key是搜索树的值,val是大根堆的值

使一棵树同时满足是二叉搜索树,同时还要满足是大根堆

注意:平衡树的初始状态一般会加两个哨兵,正无穷和负无穷,防止边界问题

 

左旋和右旋操作:为了交换节点

性质:旋转后,不会影响中序遍历的顺序。

 

插入操作:按二叉搜索树的性质插入点后,给val赋值,并且如果val不满足大根堆,则用旋转操作转上去(同时还可以保证平衡树)

 

删除操作:旋转到叶节点,然后删除。注意还要维护堆的性质,故哪个子树的val更大就和哪边旋转。

模板(例题):https://www.acwing.com/problem/content/255/

#include<bits/stdc++.h>

#define fore(x,y,z) for(LL x=(y);x<=(z);x++)
#define forn(x,y,z) for(LL x=(y);x<(z);x++)
#define rofe(x,y,z) for(LL x=(y);x>=(z);x--)
#define rofn(x,y,z) for(LL x=(y);x>(z);x--)
#define pub push_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second

using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
typedef pair<LL,LL> PLL;
const int N=100010;
int INF=0x3f3f3f3f;
int n;
struct Node
{
    int l,r;
    int key,val;
    int cnt,sz;
}tr[N];
int root,idx;

int GetNode(int key)//创建节点
{
    tr[++idx].key=key;
    tr[idx].val=rand();
    tr[idx].cnt=tr[idx].sz=1;
    return idx;
}
void PushUp(int p)
{
    tr[p].sz=tr[tr[p].l].sz+tr[tr[p].r].sz+tr[p].cnt;
    
}
void Build()
{
    GetNode(-INF);
    GetNode(INF);
    root=1;
    tr[1].r=2;
    PushUp(root);
}
void zig(int &p)//右旋
//输入为引用的原因是,旋转会使当前位置的节点变化,希望将变化传出去
{
    int q=tr[p].l;
    tr[p].l=tr[q].r;
    tr[q].r=p;
    p=q;
    PushUp(tr[p].r);
    PushUp(p);
}
void zag(int &p)//左旋
{
    int q=tr[p].r;
    tr[p].r=tr[q].l;
    tr[q].l=p;
    p=q;
    PushUp(tr[p].l);
    PushUp(p);
}

void Insert(int &p,int key)
//由于需要满足堆的性质,故需要在函数里对p进行旋转,故传引用
{
    if(!p) p=GetNode(key);
    else if(tr[p].key==key) tr[p].cnt++;
    else if(tr[p].key>key)
    {
        Insert(tr[p].l,key);
        if(tr[tr[p].l].val>tr[p].val)//递归修改
        {
            zig(p);
        }
    }
    else
    {
        Insert(tr[p].r,key);
        if(tr[tr[p].r].val>tr[p].val)//递归修改
        {
            zag(p);
        }
    }
    PushUp(p);
}
void Remove(int &p,int key)
{
    if(!p) return;
    if(tr[p].key==key)
    {
        if(tr[p].cnt>1) tr[p].cnt--;
        else if(tr[p].l||tr[p].r)//不是叶子节点
        {
            //根据左右的存在性以及val的大小判断左旋还是右旋
            if(tr[p].r==0||tr[tr[p].l].val>tr[tr[p].r].val)
            {
                zig(p);
                Remove(tr[p].r,key);
            }
            else
            {
                zag(p);
                Remove(tr[p].l,key);
            }
        }
        else
        {
            p=0;//叶子节点直接删除
        }
    }
    else
    {
        if(tr[p].key>key)
        {
            Remove(tr[p].l,key);
        }
        else
        {
            Remove(tr[p].r,key);
        }
    }
    PushUp(p);
}
int GetRank(int p,int key)//返回在p为根的子树中的排名
{
    if(!p) return 0;
    if(tr[p].key==key)
    {
        return tr[tr[p].l].sz+1;
    }
    else if(tr[p].key>key)
    {
        return GetRank(tr[p].l,key);
    }
    else
    {
        return GetRank(tr[p].r,key)+tr[p].cnt+tr[tr[p].l].sz;
    }
}
int GetKey(int p,int rank)//返回在p为根的子树中排名为rank的key
{
    if(!p) return INF;
    if(tr[tr[p].l].sz>=rank) return GetKey(tr[p].l,rank);
    if(tr[tr[p].l].sz>=rank) return GetKey(tr[p].l,rank);
    if(tr[tr[p].l].sz+tr[p].cnt>=rank) return tr[p].key;
    else return GetKey(tr[p].r,rank-(tr[tr[p].l].sz+tr[p].cnt));
}
int GetPrev(int p,int key)//严格小于key的最大数
{
    if(!p) return -INF;
    if(tr[p].key>=key)
    {
        return GetPrev(tr[p].l,key);
    }
    else
    {
        return max(tr[p].key,GetPrev(tr[p].r,key));
        //max的原因是,GetPrev没找到返回-INF,找到了则比tr[u].key大
    }
}
int GetNext(int p,int key)
{
    if(!p) return INF;
    if(tr[p].key<=key)
    {
        return GetNext(tr[p].r,key);
    }
    else
    {
        return min(tr[p].key,GetNext(tr[p].l,key));
        //与GetPrev对称
    }
}
void YD()
{
    Build();
    cin>>n;
    while(n--)
    {
        int op;int x;
        cin>>op>>x;
        if(op==1)
        {
            Insert(root,x);
        }
        if(op==2)
        {
            Remove(root,x);
        }
        if(op==3)
        {
            cout<<GetRank(root,x)-1<<endl;
        }
        if(op==4)
        {
            cout<<GetKey(root,x+1)<<endl;
        }
        if(op==5)
        {
            cout<<GetPrev(root,x)<<endl;
        }
        if(op==6)
        {
            cout<<GetNext(root,x)<<endl;
        }
    }
}
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int T=1;
    //cin >> T;
    while (T--)
    {
        YD();
    }
    return 0;
}
View Code

 

标签:return,val,int,tr,else,treap,算法,key,AcWing
From: https://www.cnblogs.com/ydUESTC/p/16739396.html

相关文章

  • DFS算法练习 POJ1111; POJ1129; POJ2245; POJ2657
    POJ1111:importjava.util.Scanner;/***@Authorjinjun99*@DateCreatedin2022/9/279:49*@Description*@Sinceversion-1.0*/publicclassMain{......
  • 16 -- 排序算法之插入排序
    算法介绍:插入排序属于内部排序法,时对于待排序的元素以插入的方式找到改元素的适当位置,以达到排序的目的。【类似于生活中的斗地主游戏,每抓起一张牌按照便把改张牌按照指定......
  • 克鲁斯卡尔算法
    应用场景某城市新增7个站点(A,B,C,D,E,F,G),现在需要修路把7个站点连通各个站点的距离用边线表示(权),比如A–B距离12公里问:如何修路保证各个站点都能连通......
  • AcWing 算法提高课 可持久化
    可持久化的前提:数据结构本身的拓扑结构不变trie、线段树、树状数组、堆等都可持久化平衡树(一般)需要左旋和右旋,不可持久化  可持久化希望将数据结构的全部修改记录下......
  • 分布式自增ID算法Snowflake简介
    背景过去的项目开发中,我们常常选用的数据库是mysql,mysql以其体积小、速度快等优势,备受中小型项目的青睐。随着项目数据量的迅速增长,mysql已无法满足我们的项目需求,数据迁移......
  • 贪心算法
    应用实例假设存在如下表的需要付费的广播台,以及广播台信号可以覆盖的地区。如何选择最少的广播台,让所有的地区都可以接收到信号思路分析目前并没有算法可以快速......
  • 基于遗传算法的物流管理系统
    原型是车辆路径规划问题(VRP)使用SpringBoot+ElementUI+MySQL搭建网站。登录页面:有三个选项,对应三种用户登录,会进入不同页面。修改密码页面:可以修改多项用户信息,和登......
  • JS 算法
    1、js统计一个字符串出现频率最高的字母/数字letstr='absafdaf234234323232'leta=[...str]//alert(ainstanceofArray)conststrChar=......
  • 前端加密算法之SM4
    1、简介1.1、国产加密算法,是一个分组算法,该算法的分组长度为128bit,密钥长度为128bit,SM4算法与AES算法具有相同的密钥长度分组长度128比特,因此在安全性上高于3DES算......
  • 算法和空间复杂度分析
    看代码:1intcal(intn){2intsum=0;3inti=1;4for(;i<=n;++i){5sum=sum+i;6}7returnsum;8从cpu角度来看,这段代码每一行都执行......