洛谷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 }

 

转载于:https://www.cnblogs.com/asdfsag/p/11097442.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值