函數式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;
}
發佈了60 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章