UVA 12538(树堆)可持久化treap

树堆的典型范例
二叉排序树+堆
所有操作围绕mergesplit两个操作进行

treep跟i笛卡尔树的结构上是相同的,只是两者的应用不同,treap的Value是随机值,为了使树更加平衡引起的,而笛卡尔树的value是一个确定值。
不懂笛卡尔树的可以看这
传送们

#include<iostream>
#include<sstream>
#include<queue>
#include<vector>
#include<ctime>
#include<cstdlib>
#include<cstring>
#include<cstdio>

using namespace std;

const int maxn=50005;

struct node;

node *null,*root[maxn];

struct node
{
    node* c[2];
    char v;
    int r,sz;
    void up(){
        sz=c[0]->sz+c[1]->sz+1;
    }
    node(char v=0):v(v){
        sz=1;
        r=rand();
        c[0]=c[1]=null;
    }
};

inline void copy(node* &a,node* b)
{
    if(b==null){
        a=b;
    }
    else a=new node(),*a=*b;
}

void merge(node* &o,node* a,node *b)
{
    if(a==null)
        copy(o,b);
    else if(b==null)
        copy(o,a);
    else if(a->r<b->r){
        copy(o,a);
        merge(o->c[1],a->c[1],b);
        o->up();
    }
    else{
        copy(o,b);
        merge(o->c[0],a,b->c[0]);
        o->up();
    }
}

void split(node* o,node* &a,node* &b,int k)//将树堆o的前k个节点变为数堆a,剩下节点变为数堆b,
{
    if(!k){
        copy(b,o);
        a=null;
    }
    else if(o->sz<=k){
        copy(a,o);
        b=null;
    }else if(o->c[0]->sz>=k){
        copy(b,o);
        split(o->c[0],a,b->c[0],k);
        b->up();
    }else{
        copy(a,o);
        split(o->c[1],a->c[1],b,k-o->c[0]->sz-1);
        a->up();
    }
}

char s[203];

void build(node* &o,int l,int r)
{
    if(l>r)
        return;
    int m=(l+r)>>1;
    o=new node(s[m]);
    build(o->c[0],l,m-1);
    build(o->c[1],m+1,r);
    o->up();
}

void ins(node* &o,node* pre,int pos) // 在pre的pos位置插入字串s,形成新树堆o
{
    node *a,*b,*c;
    int len=strlen(s);
    split(pre,a,b,pos);
    build(c,0,len-1);
    merge(a,a,c);
    merge(o,a,b);
}

void del(node* &o,node* pre,int pos,int len)
{
    node *a,*b,*c;
    split(pre,a,b,pos-1);
    split(b,b,c,len);
    merge(o,a,c);
}

int dlt; //字符c的个数

void out(node* o)
{
    if(o==null) return ;
    out(o->c[0]);
    if(o->v=='c') dlt++;
    printf("%c",o->v);
    out(o->c[1]);
}

void out(node *o,int pos,int len)       //输出树堆o中从pos位置开始的len个字符。
{
    node *a,*b,*c;
    split(o,a,b,pos-1);
    split(b,b,c,len);
    out(b);
    puts("");
}

void init()
{
    null=new node();
    null->sz=0;
    for(int i=0;i<maxn;i++)
        root[i]=null;
}

int n;

int main()
{
    scanf("%d",&n);
    init();
    int op,pos,len,v,nowv=0;
    while(n--){
        scanf("%d",&op);
        if(op==1){
            scanf("%d%s",&pos,s);
            pos-=dlt;
            ins(root[nowv+1],root[nowv],pos);
            nowv++;
        }else if(op==2){
            scanf("%d%d",&pos,&len);
            pos-=dlt;len-=dlt;
            del(root[nowv+1],root[nowv],pos,len);
            nowv++;
        }else{
            scanf("%d%d%d",&v,&pos,&len);
            v-=dlt;pos-=dlt;len-=dlt;
            out(root[v],pos,len);
        }
    }
    return 0;
}
/*
6
1 0 abcdefgh
2 4 3
3 1 2 5
3 3 3 4
1 4 xy
3 5 4 6
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值