可持久化线段树

宏定义

  • #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 个历史版本的根。
  • Edge a[i]\texttt{Edge a[i]}:节点 ii 的信息。
  • int a[i].l\texttt{int a[i].l}:节点 ii 维护的区间的左端点。
  • int a[i].r\texttt{int a[i].r}:节点 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 的值。

函数

  • Persistable_Segment_Tree()\texttt{Persistable\_Segment\_Tree()}:初始化节点个数。
  • void build(int p,int l,int r)\texttt{void build(int p,int l,int r)}:在外调用时,表示以节点 pp 为根,建议一颗区间范围为 lrl\sim r 的线段树,要求 l,rl,r 不为 00
  • int change(int fp,int x,int v)\texttt{int change(int fp,int x,int v)}:将位置为 xx 的数改为 vvfpfp 为上一个历史版本中维护该区间的点的编号,返回新版本中维护该区间的点的编号。
  • int ask(int p,int x)\texttt{int ask(int p,int x)}:询问 pp 可以访问的节点中位置 xx 上的数值。

代码

#define pl a[p].tl
#define pr a[p].tr
struct Persistable_Segment_Tree{
	int tot,root[N*20];
	struct Edge{
		int l,r,tl,tr;
		int val;
	}a[N*20];
	Persistable_Segment_Tree(){
		tot=0;
	}
	void build(int p,int l,int r){
		if(l){
			a[p=++tot].l=l;
			a[p].r=r;
		}
		if(a[p].l==a[p].r){
			a[p].val=0;
			return;
		}
		int mid=(a[p].l+a[p].r)>>1;
		pl=++tot;a[pl].l=a[p].l;a[pl].r=mid;
		pr=++tot;a[pr].l=mid+1;a[pr].r=a[p].r;
		build(pl,0,0);build(pr,0,0);
	}
	int change(int fp,int x,int v){
		int p=++tot;
		a[p]=a[fp];
		if(a[p].l==a[p].r){
			a[p].val=v;
			return p;
		}
		int mid=(a[p].l+a[p].r)>>1;
		if(x<=mid)
			pl=change(a[fp].tl,x,v);
		else
			pr=change(a[fp].tr,x,v);
		return p;
	}
	int ask(int p,int x){
		if(a[p].l==a[p].r)
			return a[p].val;
		int mid=(a[p].l+a[p].r)>>1;
		if(x<=mid)
			return ask(pl,x);
		else
			return ask(pr,x);
	}
}tree;
posted @ 2022-05-21 19:02  luckydrawbox  阅读(10)  评论(0)    收藏  举报  来源