可持久化文艺平衡树

调了我一整个上午,害得我写不了带返回\(split\),罪大恶极
首先,什么是\(FHQ\)_\(treap\),什么是可持久化,就不用多说了,本文旨在替本人保存代码,本文旨在总结打代码时的坑点。

  1. 通常来说,可持久化的主要体现——克隆,主要发生在插入、删除、修改等时,但是,由于\(FHQ\)_\(treap\)的实现依赖于\(split\)\(merge\)操作,所以主要在\(split\)时克隆即可(\(merge\)甚至都不必克隆,引用不会产生新节点,只是合并)
  2. 此外,在打翻转懒标记时克隆即可
  3. 带返回\(split\)似乎不能打(我原始版本就打的这个,但是无论怎么都调不对)
#include<iostream>
#include<random>
#define int long long

using namespace std;

const int N=2e5+5;
mt19937_64 Rand(time(0));
struct node{
	node *l,*r;
	int val,siz,sum,pri,tag;
	
	node(int v): l(nullptr),r(nullptr),val(v),siz(1),sum(v),pri(Rand()),tag(0){}
	void pushup(){
		siz=1;
		sum=val;
		if(l!=nullptr){
			siz+=l->siz;
			sum+=l->sum;
		}
		if(r!=nullptr){
			siz+=r->siz;
			sum+=r->sum;
		}
	}
};
node *rt[N];
struct FHQ_treap{
	node *clone(node *u){
		if(u==nullptr) return nullptr;
		auto tmp=new node(u->val);
		tmp->l=u->l;
		tmp->r=u->r;
		tmp->siz=u->siz;
		tmp->pri=u->pri;
		tmp->tag=u->tag;
		tmp->sum=u->sum;
		return tmp;
	}
	void pushdown(node *u){
		if(u==nullptr || !u->tag) return ;
		swap(u->l,u->r);
		if(u->l!=nullptr){
			u->l=clone(u->l);
			u->l->tag^=1;
		}
		if(u->r!=nullptr){
			u->r=clone(u->r);
			u->r->tag^=1;
		}
		u->tag=0;
	}
	int getsiz(node *u){
		if(u==nullptr) return 0;
		return u->siz;
	}
	int getsum(node *u){
		if(u==nullptr) return 0;
		return u->sum;
	}
	void split(node *u,int k,node *&x,node *&y){
	//split实质上是按照一定的条件,将整棵树分为x树和y树
		if(u==nullptr){
			x=y=nullptr;
			return ;
		}
		pushdown(u);
		int lsiz=getsiz(u->l);
		if(lsiz+1<=k){
			x=clone(u);
			// 当前节点u归入x树,并向右子树递归分裂
			split(u->r,k-lsiz-1,x->r,y);
			x->pushup();
		}
		else{
			y=clone(u);
			//同上
			split(u->l,k,x,y->l);
			y->pushup();
		}
	}
	node *merge(node *u,node *v){
		if(u==nullptr) return v;
		if(v==nullptr) return u;
		pushdown(u);
		pushdown(v);
		if(u->pri>v->pri){
			u->r=merge(u->r,v);
			u->pushup();
			return u;
		}
		else{
			v->l=merge(u,v->l);
			v->pushup();
			return v;
		}
	}
	void insert(node *&u,int pos,int val){
		node *ltr,*rtr;
		split(u,pos,ltr,rtr);
		u=merge(merge(ltr,new node(val)),rtr);
	}
	void erase(node *&u,int pos){
		node *ltr,*rtr,*mid;
		split(u,pos,mid,rtr);
		split(mid,pos-1,ltr,mid);
		delete mid;
		u=merge(ltr,rtr);
	}
	void reverse(node *&u,int l,int r){
		node *ltr,*rtr,*mid;
		split(u,r,mid,rtr);
		split(mid,l-1,ltr,mid);
		if(mid!=nullptr){
			mid=clone(mid);
			mid->tag^=1;
		}
		u=merge(merge(ltr,mid),rtr);
	}
	int query(node *u,int l,int r){
		node *ltr,*rtr,*mid;
		split(u,r,mid,rtr);
		split(mid,l-1,ltr,mid);
		int res=getsum(mid);
		u=merge(merge(ltr,mid),rtr);
		return res;
	}
};
FHQ_treap tr;

signed main(){
	cin.tie(nullptr)->sync_with_stdio(false);
	int n,last=0;
	cin>>n;
	for(int i=1;i<=n;i++){
		int v,opt;
		cin>>v>>opt;
		rt[i]=rt[v];
		if(opt==1){
			int p,x;
			cin>>p>>x;
			p^=last;
			x^=last;
			tr.insert(rt[i],p,x);
		}
		if(opt==2){
			int p;
			cin>>p;
			p^=last;
			tr.erase(rt[i],p);
		}
		if(opt==3){
			int l,r;
			cin>>l>>r;
			l^=last;
			r^=last;
			tr.reverse(rt[i],l,r);
		}
		if(opt==4){
			int l,r;
			cin>>l>>r;
			l^=last;
			r^=last;
			last=tr.query(rt[i],l,r);
			cout<<last<<'\n';
		}
	}
}

posted on 2026-02-05 15:39  _CENSORED  阅读(0)  评论(0)    收藏  举报

导航