首页 > 其他分享 >旋转Treap

旋转Treap

时间:2023-06-15 21:55:36浏览次数:33  
标签:return cur int nullptr son Treap num 旋转

splay 是通过 splay 操作均摊复杂度,而旋转 treap 也旋转,但是是通过随机赋权使得复杂度在期望下正确。

具体来说就是再随机赋一个权值 \(rank\) ,通过旋转使得这棵树的 \(val\) 满足二叉搜索树且 \(rank\) 满足小根堆。

具体来说,在查询的时候是不旋转的,只有在插入和删除时有旋转。

插入时正常往里插,回溯维护的时候,判断 \(rank\) 是否满足小根堆的性质,不满足就转一下。

删除时正常删,到要删除一个节点时,如果左右儿子不全有,那么就直接删,然后回溯维护 \(siz\) ;如果左右儿子都出现 ,那么把 \(rank\) 小的专上来,然后递归删除转下去的目前节点。

代码如下(指针实现):

```cpp
#include<bits/stdc++.h>
using namespace std;
#if linux
    random_device RD;
    mt19937_64 rnd(RD());
#else
    mt19937_64 rnd(time(0));
#endif
struct node{
    node* son[2];
    int val,cnt,siz;
    uint_fast64_t rank;
    node(int num=0){val=num,cnt=siz=1,rank=rnd(),son[0]=son[1]=nullptr;}
    void upt(){
		siz=cnt+(son[0]!=nullptr?son[0]->siz:0)+(son[1]!=nullptr?son[1]->siz:0);
	}
};
class Treap{
    private:
        node* root=nullptr;
        void rotate(node* &cur,int dir){// 0 right,1 left
            node* x=cur->son[dir];
            cur->son[dir]=x->son[dir^1];
            x->son[dir^1]=cur;
            cur->upt();
            x->upt();
            cur=x;
        }
        void _ins(node* &cur,int num){
            if (cur==nullptr){
                cur=new node(num);
                return;
            }
            if (num==cur->val){
                ++cur->cnt;
                ++cur->siz;
                return;
            }
            if (num<cur->val){
                _ins(cur->son[0],num);
                if (cur->son[0]->rank<cur->rank) rotate(cur,0);
                cur->upt();
            }
            else{
                _ins(cur->son[1],num);
                if (cur->son[1]->rank<cur->rank) rotate(cur,1);
                cur->upt();
            }
        }
        void _del(node* &cur,int num){
            if (cur==nullptr) return;
            if (num<cur->val){
                _del(cur->son[0],num);
                cur->upt();
                return;
            }
            if (num>cur->val){
                _del(cur->son[1],num);
                cur->upt();
                return;
            }
            if (cur->cnt>1){
                --cur->cnt;
                --cur->siz;
                return;
            }
            node* tmp=cur;
            if (cur->son[0]==nullptr && cur->son[1]==nullptr){
                cur=nullptr;
                delete tmp;
            }
            else if (cur->son[0]==nullptr && cur->son[1]!=nullptr){
                cur=cur->son[1];
                delete tmp;
            }
            else if (cur->son[0]!=nullptr && cur->son[1]==nullptr){
                cur=cur->son[0];
                delete tmp;
            }
            else{
                int dir=cur->son[0]->rank<cur->son[1]->rank?1:0;
                rotate(cur,dir);
                _del(cur->son[dir^1],num);
                cur->upt();
            }
        }
        int _askrk(node* cur,int num){
            if (cur==nullptr) return 1;
            int less_siz=cur->son[0]==nullptr?0:cur->son[0]->siz;
            if (cur->val==num) return less_siz+1;
            if (num<cur->val) return _askrk(cur->son[0],num);
            return less_siz+cur->cnt+_askrk(cur->son[1],num);
        }
        int _asknum(node* cur,int rk){
            int less_siz=cur->son[0]==nullptr?0:cur->son[0]->siz;
            if (rk<=less_siz) return _asknum(cur->son[0],rk);
            if (rk<=less_siz+cur->cnt) return cur->val;
            return _asknum(cur->son[1],rk-less_siz-cur->cnt);
        }
        int pre_tmp,suf_tmp;
        int _askpre(node* cur,int num){
            if (num<=cur->val){
                if (cur->son[0]!=nullptr) return _askpre(cur->son[0],num);
            }
            else{
                pre_tmp=cur->val;
                if (cur->son[1]!=nullptr) _askpre(cur->son[1],num);
                return pre_tmp;
            }
            return -1e9;
        }
        int _asksuf(node* cur,int num){
            if (num>=cur->val){
                if (cur->son[1]!=nullptr) return _asksuf(cur->son[1],num);
            }
            else{
                suf_tmp=cur->val;
                if (cur->son[0]!=nullptr) _asksuf(cur->son[0],num);
                return suf_tmp;
            }
            return 1e9;
        }
    public:
        void ins(int num){_ins(root,num);}
        void del(int num){_del(root,num);}
        int askrk(int num){return _askrk(root,num);}
        int asknum(int rk){return _asknum(root,rk);}
        int askpre(int num){return _askpre(root,num);}
        int asksuf(int num){return _asksuf(root,num);}
}treap;
int n;
int main(){
    scanf("%d",&n);
    for (int op,x,i=1;i<=n;++i){
        scanf("%d%d",&op,&x);
        cerr<<i<<endl;
        if (op==1) treap.ins(x);
        else if (op==2) treap.del(x);
        else if (op==3) printf("%d\n",treap.askrk(x));
        else if (op==4) printf("%d\n",treap.asknum(x));
        else if (op==5) printf("%d\n",treap.askpre(x));
        else printf("%d\n",treap.asksuf(x));
    }
    return 0;
}

标签:return,cur,int,nullptr,son,Treap,num,旋转
From: https://www.cnblogs.com/jerryjiang/p/17484218.html

相关文章

  • 【剑指Offer】6、旋转数组的最小数字
    【剑指Offer】6、旋转数组的最小数字题目描述:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。NOTE:给出的所有元素都大于0,若数组......
  • 数据结构和算法——旋转打印链表
    1、问题描述输入参数nn为正整数,如输入n=5n=5,则按行打印如下的数字:2、问题的理解这个问题是将数字1…n21…n2按照一圈一圈的方式......
  • 【数据结构和算法面试题】左旋转字符串
    问题分析:本题是常见的旋转字符串的问题,解决的方法是两步旋转的方法:方法:voiddo_reverse(char*p_start,char*p_end){ if(NULL==p_start||NULL==p_end||p_start>p_end)return; chartmp; while(p_start<p_end){ tmp=*p_start; *p_start=*p_end; *p_end......
  • 代码随想录算法训练营第七天| 344.反转字符串 、 541. 反转字符串II、 剑指Offer 05.
     344.反转字符串代码:1voidreverseString(vector<char>&s){23inti=0;4intj=s.size()-1;5while(i<j)6{7charmid=s[i];8s[i]=s[j];9s[j]=mid;1011i++;12......
  • 非旋TREAP
    非旋TREAP目录非旋TREAP一、TREAP—新的树形结构1.treap=tree+heap2.更优秀的时间复杂度3.treap的基础打法1.基本框架-开数组2.动态开点3.sz的维护4.分离和统一4.treap的进阶使用1.treap相比于线段树的好处2.在treap上pushup和pushdown1.总体规则1.在自己做了标记的事后下传标记,......
  • 使用NSTimer和CGAffineTransformMakeRotation实现旋转动画
     使用NSTimer和CGAffineTransformMakeRotation实现旋转动画 首先定义需要用到的变量   floatangle;   NSTimer*timer; #pragmamark------------------->旋转图片<--------------------(void)_doRotateImage{//演员初始化UIImageView*ivImage=[[UII......
  • Python视频处理案例六则:旋转视频、调整音量/播放速度、淡入淡出、插入转场素材...
    环境配置请参考:Python视频处理案例三则:剪辑与拼接、提取音频、添加字幕==============应用1、旋转视频运行结果:应用2、调整视频中的音量应用3、视频中颜色变换应用4、调整播放速度,1.5倍速应用5、淡入淡出并插入转场视频应用6、淡入淡出并插入转场图片公众号“Python小屋”......
  • Treap 模板代码
    structNode{ intpri,data,num,sz,ch[2],fa;}t[maxn];intpos;structTreap{ introot; intnewNode(intx){ t[++pos]=(Node){rand(),x,1,1,0,0,0}; returnpos; } voidupdate(intx){ t[x].sz=t[t[x].ch[0]].sz+t[t[x].ch[1]].sz+......
  • 判断一个字符串是否由另一个字符串旋转而成
    ifs1="stackoverflow"thenthefollowingaresomeofitsrotatedversions:"tackoverflows""ackoverflowst""overflowstack"whereas"stackoverflwo"isnotarotatedversion. 通常的做法algorithmcheckRot......
  • 百度随机阴影旋转验证码破解
    之前我百度没有阴影的旋转验证码,有小伙伴反馈他那里的百度验证码是有随机阴影的,原本的不带阴影的识别效果很差。所以专门针对性的做了开发识别。没有随机阴影的可以看这一篇博客《百度旋转验证码破解》识别效果可视化展示这种带随机阴影的验证码和之前没有阴影的有一点差异,特别......