基本操作
函數式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;
}