洛谷P5055 可持久化文艺平衡树 (可持久化treap)
文艺平衡树的可持久化版,可以使用treap实现。
作为序列使用的treap相对splay的优点如下:
1.代码短
2.容易实现可持久化
3.边界处理方便(splay常常需要在左右两端加上保护结点以防越界,而treap一般不用)
可以分裂合并的treap一般称作无旋treap或FHQ-treap,不过我个人觉得它的结构和普通的treap没什么两样,只是多了个分裂和合并的操作而已...
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=2e7+10,inf=0x3f3f3f3f; 5 int ch[N][2],val[N],siz[N],rd[N],rev[N],tot,n,m,rt[N]; 6 ll sum[N]; 7 #define l(u) ch[u][0] 8 #define r(u) ch[u][1] 9 int newnode(int x) {int u=++tot; val[u]=sum[u]=x,siz[u]=1,rd[u]=rand(),l(u)=r(u)=rev[u]=0; return u;} 10 int cpy(int u) {int w=++tot; val[w]=val[u],sum[w]=sum[u],rd[w]=rd[u],siz[w]=siz[u],rev[w]=rev[u],l(w)=l(u),r(w)=r(u); return w;} 11 void pu(int u) {siz[u]=siz[l(u)]+siz[r(u)]+1,sum[u]=sum[l(u)]+sum[r(u)]+val[u];} 12 void pd(int u) { 13 if(rev[u]) { 14 rev[u]=0; 15 if(l(u))l(u)=cpy(l(u)); 16 if(r(u))r(u)=cpy(r(u)); 17 swap(l(u),r(u)); 18 rev[l(u)]^=1,rev[r(u)]^=1; 19 } 20 } 21 void sp(int w,int k,int& u,int& v) { 22 if(!w) {u=v=0; return;} 23 pd(w); 24 if(k>=siz[l(w)]+1)u=cpy(w),sp(r(w),k-(siz[l(w)]+1),r(u),v),pu(u); 25 else v=cpy(w),sp(l(w),k,u,l(v)),pu(v); 26 } 27 void mg(int& w,int u,int v) { 28 if(!u||!v) {w=u|v; return;} 29 if(rd[u]>rd[v])pd(u),w=u,mg(r(w),r(u),v); 30 else pd(v),w=v,mg(l(w),u,l(v)); 31 pu(w); 32 } 33 void rv(int& u,int l,int r) { 34 int L,M,R; 35 sp(u,r,L,R),sp(L,l-1,L,M); 36 rev[M]^=1; 37 mg(u,L,M),mg(u,u,R); 38 } 39 void ins(int& u,int p,int x) { 40 int L,M,R; 41 sp(u,p,L,R),mg(L,L,newnode(x)),mg(u,L,R); 42 } 43 void del(int& u,int p) { 44 int L,M,R; 45 sp(u,p,L,R),sp(L,p-1,L,M),mg(u,L,R); 46 } 47 ll qry(int& u,int l,int r) { 48 int L,M,R; 49 sp(u,r,L,R),sp(L,l-1,L,M); 50 ll ret=sum[M]; 51 mg(L,L,M),mg(u,L,R); 52 return ret; 53 } 54 int main() { 55 srand(time(0)); 56 scanf("%d",&n); 57 ll last=0; 58 for(int i=1; i<=n; ++i) { 59 int a,b,c,d; 60 scanf("%d%d%d",&a,&b,&c),c^=last; 61 if(b!=2)scanf("%d",&d),d^=last; 62 rt[i]=rt[a]; 63 if(b==1)ins(rt[i],c,d); 64 else if(b==2)del(rt[i],c); 65 else if(b==3)rv(rt[i],c,d); 66 else printf("%lld\n",last=qry(rt[i],c,d)); 67 } 68 return 0; 69 }
还有一种实现方法是去掉每个结点的随机因子,在合并的时候改用rand函数来决定哪个结点作为哪个节点的父亲,判断rand()%(siz[u]+siz[v])和siz[u]的大小关系就行了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=2e7+10,inf=0x3f3f3f3f; 5 int ch[N][2],val[N],siz[N],rev[N],tot,n,m,rt[N]; 6 ll sum[N]; 7 #define l(u) ch[u][0] 8 #define r(u) ch[u][1] 9 int newnode(int x) {int u=++tot; val[u]=sum[u]=x,siz[u]=1,l(u)=r(u)=rev[u]=0; return u;} 10 int cpy(int u) {int w=++tot; val[w]=val[u],sum[w]=sum[u],siz[w]=siz[u],rev[w]=rev[u],l(w)=l(u),r(w)=r(u); return w;} 11 void pu(int u) {siz[u]=siz[l(u)]+siz[r(u)]+1,sum[u]=sum[l(u)]+sum[r(u)]+val[u];} 12 void pd(int u) { 13 if(rev[u]) { 14 rev[u]=0; 15 if(l(u))l(u)=cpy(l(u)); 16 if(r(u))r(u)=cpy(r(u)); 17 swap(l(u),r(u)); 18 rev[l(u)]^=1,rev[r(u)]^=1; 19 } 20 } 21 void sp(int w,int k,int& u,int& v) { 22 if(!w) {u=v=0; return;} 23 pd(w); 24 if(k>=siz[l(w)]+1)u=cpy(w),sp(r(w),k-(siz[l(w)]+1),r(u),v),pu(u); 25 else v=cpy(w),sp(l(w),k,u,l(v)),pu(v); 26 } 27 void mg(int& w,int u,int v) { 28 if(!u||!v) {w=u|v; return;} 29 if(rand()%(siz[u]+siz[v])<siz[u])pd(u),w=u,mg(r(w),r(u),v); 30 else pd(v),w=v,mg(l(w),u,l(v)); 31 pu(w); 32 } 33 void rv(int& u,int l,int r) { 34 int L,M,R; 35 sp(u,r,L,R),sp(L,l-1,L,M); 36 rev[M]^=1; 37 mg(u,L,M),mg(u,u,R); 38 } 39 void ins(int& u,int p,int x) { 40 int L,M,R; 41 sp(u,p,L,R),mg(L,L,newnode(x)),mg(u,L,R); 42 } 43 void del(int& u,int p) { 44 int L,M,R; 45 sp(u,p,L,R),sp(L,p-1,L,M),mg(u,L,R); 46 } 47 ll qry(int& u,int l,int r) { 48 int L,M,R; 49 sp(u,r,L,R),sp(L,l-1,L,M); 50 ll ret=sum[M]; 51 mg(L,L,M),mg(u,L,R); 52 return ret; 53 } 54 int main() { 55 srand(time(0)); 56 scanf("%d",&n); 57 ll last=0; 58 for(int i=1; i<=n; ++i) { 59 int a,b,c,d; 60 scanf("%d%d%d",&a,&b,&c),c^=last; 61 if(b!=2)scanf("%d",&d),d^=last; 62 rt[i]=rt[a]; 63 if(b==1)ins(rt[i],c,d); 64 else if(b==2)del(rt[i],c); 65 else if(b==3)rv(rt[i],c,d); 66 else printf("%lld\n",last=qry(rt[i],c,d)); 67 } 68 return 0; 69 }