非旋转 Treap/fhq Treap

权值版

宏定义

  • #define fhqT int:以 fhqT\text{fhqT} 为基本类型维护,可根据自己需要定义,这里实现了以 int\text{int} 为基本类型的 Treap\text{Treap}
  • #define pl a[p].lfhq Treap\text{fhq Treap} 中左子树的简写。
  • #define pr a[p].rfhq Treap\text{fhq Treap} 中右子树的简写。

常量与变量

  • int\text{int} tot:实际存在的节点个数。
  • int\text{int} nc[i]:第 ii 个内存(没有被占用的节点)。
  • int\text{int} rootfhq Treap\text{fhq Treap} 的根节点,一般为 11
  • Tree\text{Tree} a[i]fhq Treap\text{fhq Treap} 的一个节点 ii
  • int\text{int} a[i].l:节点 ii 的左子节点,没有则为 00
  • int\text{int} a[i].r:节点 ii 的右子节点,没有则为 00
  • fhqT\text{fhqT} a[i].val:节点 ii 的值。
  • int\text{int} a[i].size:以节点 ii 为根的子树的元素总数(值相同的不算作一个)。
  • int\text{int} a[i].dat:随机的额外权值,以确定 fhq Treap\text{fhq Treap} 的形态。

函数

  • FHQ_Treap():初始化相关信息,不必调用。
  • void\text{void} update(int p):更新 pp 节点的 ap.sizea_p.size
  • int\text{int} get_new(fhqT val):新建一个值为 valval 的节点,返回这个节点的编号。
  • void\text{void} split(int p,fhqT val,int &x,int &y):把节点 ppvalval 值分裂。
  • int\text{int} merge(int p,int q):合并 pp 节点和 qq 节点。
  • void\text{void} insert(fhqT val):在树中插入一个值为 valval 的节点。
  • void\text{void} remove(fhqT val):删除一个值为 valval 的节点。
  • fhqT\text{fhqT} get_val(int p,int rank):找到以 pp 为根的子树中排名为 rankrank 的节点的值。
  • int\text{int} get_rank(fhqT val):找到树中值为 valval 的节点的排名。
  • fhqT\text{fhqT} get_pre(fhqT val):找到树中值为 valval 的元素的前驱的节点的值。
  • fhqT\text{fhqT} get_next(fhqT val):找到树中值为 valval 的元素的后驱的节点的值。
  • void\text{void} write(int p):输出以 pp 节点为根节点的子树的信息,按先序遍历输出,每个节点的信息包括:该节点编号,该节点值,左子节点编号及值(无则均为 00),右子节点编号及值(无则均为 00)。
#define fhqT int
#define pl a[p].l
#define pr a[p].r
struct FHQ_Treap{
	struct Tree{
		int l,r;
		fhqT val;
		int size,dat;
	}a[N],e;
	int tot,root;
	int x,y,z;
	int nc[N];
	FHQ_Treap(){
		root=0;
		tot=N-1;
		e.l=e.r=e.val=e.dat=e.size=0;
		for(int i=1;i<N;i++)
			a[i]=e,nc[i]=i;
	}
	void update(int p){
		a[p].size=a[pl].size+a[pr].size+1;
	}
	int get_new(fhqT val){
		int p=tot--;
		a[p]=e;
		a[p].val=val;
		a[p].dat=rand();
		a[p].size=1;
		return p;
	}
	void split(int p,fhqT val,int &x,int &y){
		if(!p){
			x=y=0;
			return;
		}
		if(a[p].val<=val){
			x=p;
			split(pr,val,pr,y);
		}
		else{
			y=p;
			split(pl,val,x,pl);
		}
		update(p);
	}
	int merge(int p,int q){
		if(!p||!q)
			return p+q;
		if(a[p].dat<a[q].dat){
			a[p].r=merge(a[p].r,q);
			update(p);
			return p;
		}
		a[q].l=merge(p,a[q].l);
		update(q);
		return q;
	}
	void insert(fhqT val){
		split(root,val,x,y);
		root=merge(merge(x,get_new(val)),y);
	}
	void remove(fhqT val){
		split(root,val,x,z);
        split(x,val-1,x,y);
        nc[++tot]=y;
        y=merge(a[y].l,a[y].r);
        root=merge(merge(x,y),z);
	}
	fhqT get_val(int p,int rank){
		if(rank<=a[pl].size)
			return get_val(pl,rank);
		if(rank==a[pl].size+1)
			return a[p].val;
		return get_val(pr,rank-a[pl].size-1);
	}
	int get_rank(fhqT val){
		split(root,val-1,x,y);
		int ans=a[x].size+1;
        root=merge(x,y);
        return ans;
	}
	fhqT get_pre(fhqT val){
		split(root,val-1,x,y);
		fhqT ans=get_val(x,a[x].size);
        root=merge(x,y);
        return ans;
	}
	fhqT get_next(fhqT val){
		split(root,val,x,y);
		fhqT ans=get_val(y,1);
        root=merge(x,y);
        return ans;
	}
	void write(int p){
		if(pl)
			write(pl);
		printf("%d %d %d %d %d %d\n",p,a[p].val,pl,pr,a[pl].val,a[pr].val);
		if(pr)
			write(pr);
	}
}tree;

区间版

P2042 [NOI2005] 维护数列为标准。

宏定义

  • #define fhqT int:以 fhqT\text{fhqT} 为基本类型维护,可根据自己需要定义,这里实现了以 int\text{int} 为基本类型的 Treap\text{Treap}
  • #define pl a[p].lfhq Treap\text{fhq Treap} 中左子树的简写。
  • #define pr a[p].rfhq Treap\text{fhq Treap} 中右子树的简写。

常量与变量

  • int\text{int} tot:实际存在的节点个数。
  • int\text{int} nc[i]:第 ii 个内存(没有被占用的节点)。
  • fhqT\text{fhqT} add[i]:将加入的第 ii 个数。
  • int\text{int} rootfhq Treap\text{fhq Treap} 的根节点,一般为 11
  • Tree\text{Tree} a[i]fhq Treap\text{fhq Treap} 的一个节点 ii
  • int\text{int} a[i].l:节点 ii 的左子节点,没有则为 00
  • int\text{int} a[i].r:节点 ii 的右子节点,没有则为 00
  • fhqT\text{fhqT} a[i].val:节点 ii 的值。
  • fhqT\text{fhqT} a[i].sum:以节点 ii 为根的树的值总和。
  • fhqT\text{fhqT} a[i].mx:区间最大子段和。
  • fhqT\text{fhqT} a[i].lmx:以左端点为起点的最大子段和。
  • fhqT\text{fhqT} a[i].rmx:以右端点为起点的最大子段和。
  • int\text{int} a[i].size:以节点 ii 为根的子树的元素总数(值相同的不算作一个)。
  • int\text{int} a[i].dat:随机的额外权值,以确定 fhq Treap\text{fhq Treap} 的形态。
  • int\text{int} a[i].tag1:区间赋值标记。
  • int\text{int} a[i].tag2:区间翻转标记。

函数

  • FHQ_Treap():初始化相关信息,不必调用。
  • void\text{void} update(int p):更新 pp 节点的 ap.sizea_p.size
  • int\text{int} get_new(fhqT val):新建一个值为 valval 的节点,返回这个节点的编号。
  • void\text{void} pushup(int p):把 pp 子树的信息上传。
  • void\text{void} make_same(int p,fhqT c):把以 pp 为根的子树的节点的值全部赋值为 cc
  • void\text{void} reverse(int p):把 pp 子树翻转。
  • void\text{void} pushdown(int p):下传 pp 节点的标记。
  • void\text{void} split(int p,int rank,int &x,int &y):把节点 pprankrank 排名分裂。
  • int\text{int} merge(int p,int q):合并 pp 节点和 qq 节点。
  • int\text{int} get_l_to_r(int l,int r):把区间 [l,r][l,r] 分裂出来并返回根节点的值。
  • void\text{void} merge_back():把树合并回来。
  • int\text{int} add_num(int l,int r):递归加入 addadd 数组中 llrr 的数。
  • void\text{void} insert(int rank,int n):在区间 rankrank 位置后插入 addadd 数组的前 nn 个数。
  • void\text{void} del_num(int p):删除以 pp 为根的子树。
  • void\text{void} remove(int rank,int n):删除在区间 rankrank 位置后的 nn 个数。
  • int\text{int} get_sum(int p):以 pp 为根的子树的总值和。
  • int\text{int} get_mx(int p):以 pp 为根的子树的最大子段和。
  • void\text{void} write(int p):输出以 pp 节点为根节点的子树的信息,按先序遍历输出,每个节点的信息包括:该节点编号,该节点值,左子节点编号及值(无则均为 00),右子节点编号及值(无则均为 00),注意这个操作会把所有节点 pushdown 一遍,要慎用。
#define fhqT int
#define pl a[p].l
#define pr a[p].r
struct FHQ_Treap{
	struct Tree{
		int l,r;
		fhqT val,sum,mx,lmx,rmx;
		int size,dat;
		int tag1,tag2;
	}a[N];
	int tot,root;
	int x,y,z;
	int nc[N];
	fhqT add[N];
	FHQ_Treap(){
		root=0;
		tot=N-1;
		Tree e;
		e.l=e.r=e.val=e.dat=e.size=0;
		e.sum=e.tag1=e.tag2=0;e.lmx=e.rmx=e.mx=0;
		for(int i=0;i<N;i++)
			a[i]=e,nc[i]=i;
	}
	int get_new(fhqT val){
		int p=nc[tot--];
		a[p].sum=a[p].mx=a[p].val=val;
		a[p].dat=rand();
		a[p].size=1;
		a[p].tag1=a[p].tag2=a[p].l=a[p].r=0;
		a[p].lmx=a[p].rmx=max(0,val);
		return p;
	}
	void pushup(int p){
		if(!p)
			return;
		a[p].size=a[pl].size+a[pr].size+1;
		a[p].sum=a[pl].sum+a[p].val+a[pr].sum;
		a[p].lmx=max(a[pl].lmx,a[pl].sum+a[p].val+a[pr].lmx);
		a[p].rmx=max(a[pr].rmx,a[pr].sum+a[p].val+a[pl].rmx);
		a[p].mx=a[pl].rmx+a[p].val+a[pr].lmx;
		if(pl)
			a[p].mx=max(a[p].mx,a[pl].mx);
		if(pr)
			a[p].mx=max(a[p].mx,a[pr].mx);
	}
	void make_same(int p,fhqT c){
		a[p].val=c;
		a[p].sum=a[p].size*c;
		a[p].lmx=a[p].rmx=max(0,a[p].sum);
		a[p].mx=max(c,a[p].sum);
		a[p].tag1=1;
	}
	void reverse(int p){
		swap(pl,pr);
		swap(a[p].lmx,a[p].rmx);
		a[p].tag2^=1;
	}
	void pushdown(int p){
		if(!p)
			return;
		if(a[p].tag1){
			if(pl)
				make_same(pl,a[p].val);
			if(pr)
				make_same(pr,a[p].val);
			a[p].tag1=0;
		}
		if(a[p].tag2){
			if(pl)
				reverse(pl);
			if(pr)
				reverse(pr);
			a[p].tag2=0;
		}
	}
	void split(int p,int rank,int &x,int &y){
		if(!p){
			x=y=0;
			return;
		}
		pushdown(p);
		if(a[pl].size<rank){
			x=p;
			split(pr,rank-a[pl].size-1,pr,y);
		}
		else{
			y=p;
			split(pl,rank,x,pl);
		}
		pushup(p);
	}
	int merge(int p,int q){
		if(!p||!q)
			return p+q;
		if(a[p].dat<a[q].dat){
			pushdown(p);
			a[p].r=merge(a[p].r,q);
			pushup(p);
			return p;
		}
		pushdown(q);
		a[q].l=merge(p,a[q].l);
		pushup(q);
		return q;
	}
	int get_l_to_r(int l,int r){
		split(root,l-1,x,y);
		split(y,r-l+1,y,z);
		return y;
	}
	void merge_back(){
		root=merge(merge(x,y),z);
	}
	int add_num(int l,int r){
		int mid=(l+r)>>1;
		if(l^r)
			return merge(add_num(l,mid),add_num(mid+1,r));
		return get_new(add[l]);
	}
	void insert(int rank,int n){
		split(root,rank,x,y);
		root=merge(merge(x,add_num(1,n)),y);
	}
	void del_num(int p){
		if(!p)
			return;
		nc[++tot]=p;
		del_num(pl);
		del_num(pr);
	}
	void remove(int rank,int n){
		split(root,rank-1,x,y);
        split(y,n,y,z);
        del_num(y);
        root=merge(x,z);
	}
	int get_sum(int p){
		return a[p].sum;
	}
	int get_mx(int p){
		return a[p].mx;
	}
	void write(int p){
		if(!p)
			return;
		pushdown(p);
		write(pl);
		printf("%d %d %d %d %d %d\n",p,a[p].val,pl,pr,a[pl].val,a[pr].val);
		write(pr);
	}
}tree;
posted @ 2022-02-18 13:25  luckydrawbox  阅读(9)  评论(0)    收藏  举报  来源