可持久化平衡树
可持久化平衡树
对可持久化 非旋 \(Treap\) 来说:
在复制一个节点 \(X_{a}\)(\(X\) 节点的第 \(a\) 个版本)的新版本 \(X_{a+1}\)(\(X\) 节点的第 \(a+1\) 个版本)以后:
- 如果某个儿子节点 \(Y\) 不用修改信息,那么就把 \(X_{a+1}\) 的指针直接指向 \(Y_{a}\)(\(Y\) 节点的第 \(a\) 个版本)即可。
- 反之,如果要修改 \(Y\),那么就在递归到下层时新建 \(Y_{a+1}\)(\(Y\) 节点的第 \(a+1\) 个版本)这个新节点用于存储新的信息,同时把 \(X_{a+1}\) 的指针指向 \(Y_{a+1}\)(\(Y\) 节点的第 \(a+1\) 个版本)。
可持久化普通平衡树
由于\(FHQ\) \(Treap\)中对树的形态造成影响的只有 \(Split\) 和 \(Merge\)
\(Split\) 和 \(Merge\) 操作都只会改变两颗 \(Treap\) 交接处的节点
而交接处的节点构成 \(Treap\) 上的一条链
所以我们可以在交接处新开点,然后其他点依次复制
要开50倍空间
\(split\)
il void split(cs int rt,cs int k,int &x,int &y){
if(!rt) return x=y=0,void();
if(t[rt].val<=k){
t[x=++cnt]=t[rt];
split(rs(x),k,rs(x),y);
update(x);
}
else{
t[y=++cnt]=t[rt];
split(ls(y),k,x,ls(y));
update(y);
}
}
\(merge\)
il int merge(cs int x,cs int y){
if(!x||!y) return x+y;
ri int rt=++cnt;
if(t[x].pri<t[y].pri){
t[rt]=t[x];
rs(rt)=merge(rs(rt),y);
return update(rt),rt;
}
else{
t[rt]=t[y];
ls(rt)=merge(x,ls(rt));
return update(rt),rt;
}
}
code
#include <bits/stdc++.h>
#define il inline
#define cs const
#define ri register
using namespace std;
namespace Q{
il int rd(){
ri int x=0;ri bool f=0;ri char c=getchar();
while(!isdigit(c)) f|=(c==45),c=getchar();
while(isdigit(c)) x=x*10+(c^48),c=getchar();
return f?-x:x;
}
il void wt(int x){
if(x<0) x=-x,putchar(45);
if(x>=10) wt(x/10);
return putchar(x%10|48),void();
}
il void wn(int x,char c=10){
wt(x),putchar(c);
}
} using namespace Q;
cs int N=5e5+5,inf=2147483647;
namespace fhq_treap{
#define ls(x) t[x].ch[0]
#define rs(x) t[x].ch[1]
mt19937 srd(time(0));
int cnt,rot[N];
struct tree{
int ch[2],val,pri,sz;
}t[N*50];
il int add(int val=0){
t[++cnt].val=val;
t[cnt].sz=1;
t[cnt].pri=srd();
return cnt;
}
il void update(int rt){
t[rt].sz=t[ls(rt)].sz+t[rs(rt)].sz+1;
}
il int merge(cs int x,cs int y){
if(!x||!y) return x+y;
ri int rt=++cnt;
if(t[x].pri<t[y].pri){
t[rt]=t[x];
rs(rt)=merge(rs(rt),y);
return update(rt),rt;
}
else{
t[rt]=t[y];
ls(rt)=merge(x,ls(rt));
return update(rt),rt;
}
}
il void split(cs int rt,cs int k,int &x,int &y){
if(!rt) return x=y=0,void();
if(t[rt].val<=k){
t[x=++cnt]=t[rt];
split(rs(x),k,rs(x),y);
update(x);
}
else{
t[y=++cnt]=t[rt];
split(ls(y),k,x,ls(y));
update(y);
}
}
il void ins(int &rt,cs int val){
ri int x,y; split(rt,val,x,y);
rt=merge(merge(x,add(val)),y);
}
il void del(int &rt,cs int val){
ri int x,y,z; split(rt,val,x,z),split(x,val-1,x,y);
y=merge(ls(y),rs(y)),rt=merge(merge(x,y),z);
}
il int rnk(int &rt,cs int val){
ri int x,y,rk;split(rt,val-1,x,y);
return rk=t[x].sz+1,rt=merge(x,y),rk;
}
il int kth(int rt,int k){
while(1){
if(k<=t[ls(rt)].sz) rt=ls(rt);
else if(k==t[ls(rt)].sz+1) return rt;
else k-=t[ls(rt)].sz+1,rt=rs(rt);
}
}
il int pre(int &rt,int val){
ri int x,y,as; split(rt,val-1,x,y);
as=t[kth(x,t[x].sz)].val;
return rt=merge(x,y),as;
}
il int nxt(int &rt,int val){
ri int x,y,as; split(rt,val,x,y);
as=t[kth(y,1)].val;
return rt=merge(x,y),as;
}
#undef ls
#undef rs
} using namespace fhq_treap;
signed main(){
ri int n=rd();
ins(rot[0],inf),ins(rot[0],-inf);
for(ri int i=1,op,x;i<=n;++i){
rot[i]=rot[rd()],op=rd(),x=rd();
switch (op){
case 1: ins(rot[i],x); break;
case 2: del(rot[i],x); break;
case 3: wn(rnk(rot[i],x)-1); break;
case 4: wn(t[kth(rot[i],x+1)].val); break;
case 5: wn(pre(rot[i],x)); break;
case 6: wn(nxt(rot[i],x)); break;
}
}
return 0;
}
可持久化文艺平衡树
\(Split\) 过程中对要修改的结点进行复制,在新节点上修改
\(Split\) 和 \(Merge\) 总是成对出现,只用复制一次
要看128倍空间(回收结点64倍)
\(pushdown\)
il void pushdown(int rt){
if(t[rt].lz){
if(ls(rt)) t[++cnt]=t[ls(rt)],ls(rt)=cnt; //
if(rs(rt)) t[++cnt]=t[rs(rt)],rs(rt)=cnt; //
swap(ls(rt),rs(rt)),t[rt].lz=0;
if(ls(rt)) t[ls(rt)].lz^=1;
if(rs(rt)) t[rs(rt)].lz^=1;
}
}
\(split\)
il void split(cs int rt,cs int k,int &x,int &y){
if(!rt) return x=y=0,void();
pushdown(rt);
if(t[ls(rt)].sz<k){
t[x=++cnt]=t[rt];
split(rs(x),k-t[ls(rt)].sz-1,rs(x),y);
update(x);
}
else{
t[y=++cnt]=t[rt];
split(ls(y),k,x,ls(y));
update(y);
}
}
code
#include <bits/stdc++.h>
#define il inline
#define cs const
#define ri register
#define int long long
using namespace std;
namespace Q{
il int rd(){
ri int x=0;ri bool f=0;ri char c=getchar();
while(!isdigit(c)) f|=(c==45),c=getchar();
while(isdigit(c)) x=x*10+(c^48),c=getchar();
return f?-x:x;
}
il void wt(int x){
if(x<0) x=-x,putchar(45);
if(x>=10) wt(x/10);
return putchar(x%10|48),void();
}
il void wn(int x,char c=10){
wt(x),putchar(c);
}
} using namespace Q;
cs int N=2e5+5;
namespace fhq_treap{
#define ls(x) t[x].ch[0]
#define rs(x) t[x].ch[1]
mt19937 srd(time(0));
int cnt,rot[N];
struct tree{
int ch[2],val,pri,sz,lz,sum;
}t[N<<7];
il int add(int val=0){
t[++cnt].val=val,t[cnt].sum=val;
t[cnt].sz=1,t[cnt].pri=srd();
return cnt;
}
il void update(int rt){
t[rt].sz=t[ls(rt)].sz+t[rs(rt)].sz+1;
t[rt].sum=t[ls(rt)].sum+t[rs(rt)].sum+t[rt].val;
}
il void pushdown(int rt){
if(t[rt].lz){
if(ls(rt)) t[++cnt]=t[ls(rt)],ls(rt)=cnt; //
if(rs(rt)) t[++cnt]=t[rs(rt)],rs(rt)=cnt; //
swap(ls(rt),rs(rt)),t[rt].lz=0;
if(ls(rt)) t[ls(rt)].lz^=1;
if(rs(rt)) t[rs(rt)].lz^=1;
}
}
il void split(cs int rt,cs int k,int &x,int &y){
if(!rt) return x=y=0,void();
pushdown(rt);
if(t[ls(rt)].sz<k){
t[x=++cnt]=t[rt];
split(rs(x),k-t[ls(rt)].sz-1,rs(x),y);
update(x);
}
else{
t[y=++cnt]=t[rt];
split(ls(y),k,x,ls(y));
update(y);
}
}
il int merge(cs int x,cs int y){
if(!x||!y) return x+y;
if(t[x].pri<t[y].pri){
pushdown(x);
rs(x)=merge(rs(x),y);
return update(x),x;
}
else{
pushdown(y);
ls(y)=merge(x,ls(y));
return update(y),y;
}
}
il void rev(int &rt,cs int l,cs int r){
ri int x,y,z;
split(rt,r,x,z),split(x,l-1,x,y);
t[y].lz^=1,rt=merge(merge(x,y),z);
}
il int ask(int &rt,cs int l,cs int r){
ri int x,y,z,as;
split(rt,r,x,z),split(x,l-1,x,y);
as=t[y].sum;
return rt=merge(merge(x,y),z),as;
}
il void ins(int &rt,cs int p,cs int val){
ri int x,y; split(rt,p,x,y);
rt=merge(merge(x,add(val)),y);
}
il void del(int &rt,cs int val){
ri int x,y,z;
split(rt,val,x,z);
split(x,val-1,x,y);
rt=merge(x,z);
}
#undef ls
#undef rs
} using namespace fhq_treap;
signed main(){
ri int n=rd();
for(ri int i=1,op,l,r,las=0;i<=n;++i){
rot[i]=rot[rd()],op=rd(),l=rd()^las;
switch (op){
case 1:r=rd()^las,ins(rot[i],l,r);break;
case 2:del(rot[i],l);break;
case 3:r=rd()^las,rev(rot[i],l,r);break;
case 4:r=rd()^las,wn(las=ask(rot[i],l,r));break;
}
}
return 0;
}
I went to the woods because I wanted to live deliberately, I wanted to live deep and suck out all the marrow of life, and not when I had come to die, discover that I had not live.