线段树的合并与分裂

宏定义

  • #define pl a[p].tl\texttt{\#define pl a[p].tl}:节点 pp 的左儿子。
  • #define pr a[p].tr\texttt{\#define pr a[p].tr}:节点 pp 的右儿子。

常量与变量

  • int tot\texttt{int tot}:节点个数。
  • int root[i]\texttt{int root[i]}:第 ii 个线段树的根。
  • int cnt\texttt{int cnt}:被删除过的冗余节点的个数。
  • int nc[i]\texttt{int nc[i]}:第 ii 个可再用的冗余节点。
  • Tree a[i]\texttt{Tree a[i]}:节点 ii 的信息。
  • int a[i].tl\texttt{int a[i].tl}:节点 ii 的左儿子。
  • int a[i].tr\texttt{int a[i].tr}:节点 ii 的右儿子。
  • int a[i].val\texttt{int a[i].val}:节点 ii 管理的权值区间的数的个数。

函数

  • Segment_Tree()\texttt{Segment\_Tree()}:初始化节点个数。
  • int get_new()\texttt{int get\_new()}:得到一个新节点的编号并占用此节点。
  • void del(int p)\texttt{void del(int p)}:删除 pp 节点并清除它的信息。
  • void add(int p,int x,int v,int L,int R)\texttt{void add(int p,int x,int v,int L,int R)}:将权值区间为 [L,R][L,R] 的节点 pp 中权值为 xx 的数的个数增加 vv 个。
  • long long asksum(int p,int l,int r,int L,int R)\texttt{long long asksum(int p,int l,int r,int L,int R)}:求权值区间为 [L,R][L,R] 的节点 pp 中权值在 [l,r][l,r] 中的数的个数。
  • int askkth(int p,int k,int L,int R)\texttt{int askkth(int p,int k,int L,int R)}:求权值区间为 [L,R][L,R] 的节点 pp 中第 kk 小数的值。
  • int merge(int x,int y)\texttt{int merge(int x,int y)}:合并树根 xxyy 并删除 yy
  • void split(int p,int x,ll k)\texttt{void split(int p,int x,ll k)}:将 pp 中比第 kk 小数大的数都分裂到节点 xx 中。

代码

#define pl a[p].tl
#define pr a[p].tr
struct Segment_Tree{
	int tot,root[N],cnt,nc[N<<6];
	struct Tree{
		int tl,tr;
		ll val;
	}a[N<<6];
	Segment_Tree(){
		tot=0;
	}
	int get_new(){
		return cnt?nc[cnt--]:++tot;
	}
	void del(int p){
		nc[++cnt]=p;
		a[p].tl=a[p].tr=a[p].val=0;
	}
	void pushup(int p){
		a[p].val=a[pl].val+a[pr].val;
	}
	void add(int p,int x,int v,int L,int R){
		if(L==R){
			a[p].val+=v;
			return;
		}
		int mid=(L+R)>>1;
		if(x<=mid){
			if(!pl)
				pl=get_new();
			add(pl,x,v,L,mid);
		}
		else{
			if(!pr)
				pr=get_new();
			add(pr,x,v,mid+1,R);
		}
		pushup(p);
	}
	long long asksum(int p,int l,int r,int L,int R){
		if(l<=L&&R<=r)
			return a[p].val;
		int mid=(L+R)>>1;
		ll ans=0;
		if(!pl)
			pl=get_new();
		if(!pr)
			pr=get_new();
		if(l<=mid)
			ans+=asksum(pl,l,r,L,mid);
		if(r>mid)
			ans+=asksum(pr,l,r,mid+1,R);
		return ans;
	}
	int askkth(int p,int k,int L,int R){
		if(L==R)
			return L;
		int mid=(L+R)>>1;
		if(a[pl].val>=k)
			return askkth(pl,k,L,mid);
		else
			return askkth(pr,k-a[pl].val,mid+1,R);
	}
	int merge(int x,int y){
		if(!x||!y)
			return x+y;
		a[x].val+=a[y].val;
		a[x].tl=merge(a[x].tl,a[y].tl);
		a[x].tr=merge(a[x].tr,a[y].tr);
		del(y);
		return x;
	}
	void split(int p,int x,ll k){
		ll v=a[pl].val;
		if(k>v){
			a[x].tr=get_new();
			split(pr,a[x].tr,k-v);
		}
		else
			swap(pr,a[x].tr);
		if(k<v){
			a[x].tl=get_new();
			split(pl,a[x].tl,k);
		}
		a[x].val=a[p].val-k;
		a[p].val=k;
	}
}tree;
posted @ 2022-05-27 13:11  luckydrawbox  阅读(12)  评论(0)    收藏  举报  来源