无旋treap的初步学习

无旋treap

是一种诡异的平衡树
最主要的操作
就是split(拆分成两棵子树)和merge(合并为一棵子树)

update操作

这个。。。就不讲了吧。因题而异。
所以我写出来是为了什么?

split操作

分为两种
一种是以前k个和剩下的来拆分,适用于区间操作时

//r1为前k个的子树的根,r2为剩下的子树的根
void split_treap(int x,int k,int& r1,int& r2){
    if(!x){
        r1=0,r2=0;
        return ;
    }
    int sz=tree[tree[x].l].sz;
    if(sz>=k){
        split_treap(tree[x].l,k,r1,r2);
        tree[x].l=r2;
        update(x);
        r2=x;
    }
    else{
        split_treap(tree[x].r,k-sz-1,r1,r2);
        tree[x].r=r1;
        update(x);
        r1=x;
    }
}

第二种是按照key值,适用于正常的平衡树

//r1为小于等于key值子树的根,r2为剩下的子树的根
void split_treap(int x,int val,int& r1,int& r2){
    if(!x){
        r1=0,r2=0;
        return ;
    }
    if(tree[x].key>val){
        split_treap(tree[x].l,val,r1,tree[x].l);
        update(x);
        r2=x;
    }
    else{
        split_treap(tree[x].r,val,tree[x].r,r2);
        update(x);
        r1=x;
    }
}

merge操作

把我们分出来的两个子树合在一起
注意必须当满足一棵子树中所有的key值都小于等于另一颗子树时才能合并

int merge_treap(int x,int y){
    if(!x) return y;
    if(!y) return x;
    if(tree[x].fix<tree[y].fix){
        tree[x].r=merge_treap(tree[x].r,y);
        update(x);
        return x;
    }
    else{
        tree[y].l=merge_treap(x,tree[y].l);
        update(y);
        return y;
    }
}

find_key操作

寻找第k小的值
给出一种迭代的写法

int find_key_treap(int x,int k){
    if(k>tree[x].sz)
        return INF;
    while(1){
        if(k<=tree[tree[x].l].sz)
            x=tree[x].l;
        else if(k==tree[tree[x].l].sz+1)
            return tree[x].key;
        else {
            k-=tree[tree[x].l].sz+1;
            x=tree[x].r;
        }
    }
}

find_rank操作

根据值寻找排名,如果存在多个这种值,返回最小的排名

int find_rank_treap(int x,int val){
    int r1,r2;
    split_treap(root,val-1,r1,r2);
    int ans=tree[r1].sz+1;
    root=merge_treap(r1,r2);
    return ans;
}

insert操作

新建并插入值为val的节点

void insert_treap(int val){
    int r1,r2;
    split_treap(root,val,r1,r2);
    ncnt++;
    tree[ncnt]=node(val);
    root=merge_treap(merge_treap(r1,ncnt),r2);
}

delete操作

删除值为val的节点

void delete_treap(int val){
    int r1,r2,r3,r4;
    split_treap(root,val,r1,r2);
    split_treap(r1,val-1,r3,r4);
    if(tree[r4].key!=val)//被删除的节点值不为val
        return ;
    r4=merge_treap(tree[r4].l,tree[r4].r);
    root=merge_treap(merge_treap(r3,r4),r2);
}

find_previous操作

求x的前驱(前驱定义为小于x,且最大的数)

int find_previous_treap(int val){
    int k=find_rank_treap(val);
    return find_key_treap(k-1);
}

find_next操作

求x的后继(后继定义为大于x,且最小的数)

int find_next_treap(int val){
    int r1,r2;
    split_treap(root,val,r1,r2);
    int ans=find_key_treap(r2,1);
    root=merge_treap(r1,r2);
    return ans;
}

reverse操作

把区间[l,r]翻转(比如10 30 20翻转[1,3]成20 10 30)

void reverse_treap(int l,int r){
    if(l==r)
        return ;
    int r1,r2,r3;
    split_treap(root,r,r1,r2);
    split_treap(r1,l-1,r1,r3);
    tree[r3].reverse^=1;//懒标记
    root=merge_treap(merge_treap(r1,r3),r2);
}

addup操作

求区间[1,k]的和(怎么求[l,r]我觉得就没必要说了吧)

long long sum_treap(int x,int k){
    if(!x||!k)
        return 0;
    if(k>tree[x].sz)
        return tree[x].sum;
    int sz=tree[tree[x].l].sz;
    if(k<=sz)
        return sum_treap(tree[x].l,k);
    else
        return tree[tree[x].l].sum+tree[x].key+sum_treap(tree[x].r,k-sz-1);
}

可持久化平衡树(基于无旋treap)

无旋treap相比旋转的treap,最大的区别就是不旋转(废话!)
由于不旋转,才能进行我们可持久化的改造
其实跟其他数据结构的可持久化改造类似,就是存一个root数组,并且新建节点
直接上代码吧,不懂可以看看注释
题目:洛谷3835
https://www.luogu.org/problemnew/show/3835

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int N=5*1e5+5,M=15000000;
struct node{
    int l,r,key,fix,sz;
    node(){}
    node(int _key):l(0),r(0),key(_key),fix(rand()),sz(1){}
}tree[M];
int ncnt;
int root[N];
void update(int a){
    tree[a].sz=1;
    if(tree[a].l)
        tree[a].sz+=tree[tree[a].l].sz;
    if(tree[a].r)
        tree[a].sz+=tree[tree[a].r].sz;
}
//为什么merge操作不需要新建节点呢,因为合并的一定是同时间的
int merge_treap(int x,int y){
    if(!x) return y;
    if(!y) return x;
    if(tree[x].fix<tree[y].fix){
        tree[x].r=merge_treap(tree[x].r,y);
        update(x);
        return x;
    }
    else{
        tree[y].l=merge_treap(x,tree[y].l);
        update(y);
        return y;
    }
}
//在split操作中新建节点
void split_treap(int x,int val,int& r1,int& r2){
    if(!x){
        r1=0,r2=0;
        return ;
    }
    if(tree[x].key<=val){
        split_treap(tree[x].r,val,r1,r2);
        ncnt++;
        tree[ncnt]=tree[x];
        tree[ncnt].r=r1;
        r1=ncnt;
        update(ncnt);
    }
    else{
        split_treap(tree[x].l,val,r1,r2);
        ncnt++;
        tree[ncnt]=tree[x];
        tree[ncnt].l=r2;
        r2=ncnt;
        update(ncnt);
    }
}
int find_key_treap(int x,int k){
    while(1){
        if(k<=tree[tree[x].l].sz)
            x=tree[x].l;
        else if(k==tree[tree[x].l].sz+1)
            return tree[x].key;
        else {
            k-=tree[tree[x].l].sz+1;
            x=tree[x].r;
        }
    }
}
int find_rank_treap(int&rt,int val){
    int r1,r2;
    split_treap(rt,val-1,r1,r2);
    int ans=tree[r1].sz+1;
    rt=merge_treap(r1,r2);
    return ans;
}
void insert_treap(int&rt,int val){
    int r1,r2;
    split_treap(rt,val,r1,r2);
    ncnt++;
    tree[ncnt]=node(val);
    rt=merge_treap(merge_treap(r1,ncnt),r2);
}
void delete_treap(int&rt,int val){
    int r1,r2,r3,r4;
    split_treap(rt,val,r1,r2);
    split_treap(r1,val-1,r3,r4);
    if(tree[r4].key==val)
        r4=merge_treap(tree[r4].l,tree[r4].r);
    rt=merge_treap(merge_treap(r3,r4),r2);
}
int find_previous_treap(int&rt,int val){
    int k=find_rank_treap(rt,val);
    return find_key_treap(rt,k-1);
}
int find_next_treap(int&rt,int val){
    int r1,r2;
    split_treap(rt,val,r1,r2);
    int ans=find_key_treap(r2,1);
    rt=merge_treap(r1,r2);
    return ans;
}
int main()
{
    int n;
    scanf("%d",&n);
    insert_treap(root[0],-2147483647);
    insert_treap(root[0],2147483647);
    for(int i=1;i<=n;i++){
        int be,op,x;
        scanf("%d%d%d",&be,&op,&x);
        ncnt++;
        root[i]=ncnt;
        tree[ncnt]=tree[root[be]];
        if(op==1)
            insert_treap(root[i],x);
        else if(op==2)
            delete_treap(root[i],x);
        else if(op==3)
            printf("%d\n",find_rank_treap(root[i],x)-1);
        else if(op==4)
            printf("%d\n",find_key_treap(root[i],x+1));
        else if(op==5)
            printf("%d\n",find_previous_treap(root[i],x));
        else if(op==6)
            printf("%d\n",find_next_treap(root[i],x));
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值