函数式treap

基本操作

函数式treap也就是可持久化treap,是一种可持久化数据结构。它的主要操作是merge和split,详情可以参考不基于旋转的treap。
不同之处在于我们要可持久化,所以只要将所有的修改操作变为建新节点就行了。写起来很简单,具体实现可以看看例题代码。

例题

UVA12538
题意就是要求维护一个字符串,支持插入,修改,访问历史版本。
这直接用函数式treap做就可以了。
我的实现方法与不同treap不同的在于,合并是我是按子树大小随机合并的,具体操作参见代码。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;

typedef pair<int,int>p;
typedef long long ll;
struct node{
    int data,ls,rs,size;
}t[10000010];
int root[50010],cnt,n,x,y,z,op,tot,nc;
char s[1000010];
#define updata(x) t[x].size=t[t[x].ls].size+t[t[x].rs].size+1
p split(int x,int y){
    if(x==0) return make_pair(0,0);
    int num=++cnt;
    t[num]=t[x];       //建新节点
    if(t[t[x].ls].size==y){
        t[num].ls=0; updata(num);
        return make_pair(t[x].ls,num);
    }
    if(t[t[x].ls].size+1==y){
        t[num].rs=0; updata(num);
        return make_pair(num,t[x].rs);
    }
    if(t[t[x].ls].size>y){
        p tmp=split(t[x].ls,y);
        t[num].ls=tmp.second; updata(num);
        return make_pair(tmp.first,num);
    }
    p tmp=split(t[x].rs,y-t[t[x].ls].size-1);
    t[num].rs=tmp.first; updata(num);
    return make_pair(num,tmp.second);
}
int merge(int x,int y){
    if(x==0||y==0) return x+y;
    if((ll)t[x].size*1107>=(ll)rand()%1107*(ll)(t[x].size+t[y].size)){
    //按子树大小合并
        int tmp=++cnt; t[tmp]=t[x]; //新建节点
        t[tmp].rs=merge(t[x].rs,y); 
        updata(tmp); return tmp;
    }
    int tmp=++cnt; t[tmp]=t[y];  //新建节点
    t[tmp].ls=merge(x,t[y].ls);
    updata(tmp); return tmp;
}
int make(int l,int r,char s[]){
    if(l>r) return 0;
    int mid=(l+r)>>1;
    int tmp=++cnt;
    t[tmp].data=s[mid]-'a';
    t[tmp].ls=make(l,mid-1,s);
    t[tmp].rs=make(mid+1,r,s);
    updata(tmp); return tmp;
}
void print(int x){
    if(t[x].ls) print(t[x].ls);
    putchar(t[x].data+'a');
    if(t[x].data==2) nc++;
    if(t[x].rs) print(t[x].rs);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&op);
        if(op==1){
            scanf("%d%s",&x,s); x-=nc;
            p tmp=split(root[tot],x);
            root[++tot]=merge(tmp.first,make(0,strlen(s)-1,s));
            root[tot]=merge(root[tot],tmp.second);
        } else
        if(op==2){
            scanf("%d%d",&x,&y); x-=nc; y-=nc;
            p t1=split(root[tot],y+x-1);
            p t2=split(t1.first,x-1);
            root[++tot]=merge(t2.first,t1.second);
        }else{
            scanf("%d%d%d",&x,&y,&z);
            x-=nc; y-=nc; z-=nc;
            p t1=split(root[x],z+y-1);
            p t2=split(t1.first,y-1);
            print(t2.second);
            putchar('\n');
        }
    }
    return 0;
}

你可能感兴趣的:(函数式treap)