线段树 动态开点
Posted wangyifan124
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树 动态开点相关的知识,希望对你有一定的参考价值。
在一些计数问题中,线段树用于维护值域(一段权值范围),这样的线段树也称为权值线段树。为了降低空间复杂度,我们可以不建出整棵线段树的结构,而是在最初只建立一个根节点,代表整个区间,当需要访问线段树的某棵子树(某个子区间)时,再建立代表这个子区间的节点。采用这种方法维护的线段树称为动态开点的线段树。动态开点的线段树抛弃了完全二叉树父节点的2倍编号规则,改为使用变量记录左右子节点的编号(相当于指针)。同时,它也不再保存每个节点代表的区间,而是在每次递归访问的过程中作为参数传递。下面是一个动态开点的线段树的节点结构。
struct segment_tree{ int lc,rc; //左右子节点的编号 int dat; //区间最大值 }tree[maxn<<2]; int root,tot; inline int build(){ //新建一个节点 tot++; tree[tot].lc = tree[tot].rc = tree[tot].dat = 0; } int main(){ tot = 0; root = build(); //根节点 }
下面的代码对线段树单点修改的过程稍加变动,实现了在动态开点的线段树中把val位置上的值加delta,同时维护区间最大值的操作
inline void update(int p,int l,int r,int val,int delta){ if(l == r){ tree[p].dat += delta; return; } int mid = (l+r)>>1; //代表的区间[l,r] 作为递归参数传递 if(val <= mid){ if(!tree[p].lc)tree[p].lc = build(); update(tree[p].lc,l,mid,val,delta); } else{ if(!tree[p].rc)tree[p].rc = build(); //动态开点 update(tree[p].rc,mid+1,r,val,delta); } tree[p].dat = max(tree[tree[p].lc].dat,tree[tree[p].rc].dat); }
以上是关于线段树 动态开点的主要内容,如果未能解决你的问题,请参考以下文章