权值线段树与动态开点
在正常的线段树中,我们总是以下表来进行线段树的操作。而权值线段树主要用于对具体的权值进行构造线段树,用于权值计数,权值操作等问题。
由于权值太大,我们不再采用完全二叉树的编号方式,使用类似于邻接表一样的存储方式,每一个节点只存储它儿子节点的编号;且只对有用区间进行开点操作,这样复杂度也是 l o g log log级别的。
例如,需要添加权值为为 4 4 4的点,而总区间是 [ 1 , 10 ] [1,10] [1,10];我们只需要开展区间 [ 1 , 10 ] , [ 1 , 5 ] , [ 4 , 5 ] , [ 4 , 4 ] [1,10],[1,5],[4,5],[4,4] [1,10],[1,5],[4,5],[4,4]即可。
代码如下:
void Build(int p,int l,int r,int x,int v)
{
if (l == r) {
t[p].ans = v; return; }
int mid = l+r >> 1;
if (x <= mid) {
if (t[p].lc == 0) t[p].lc = getnew();
Build(t[p].lc,l,mid,x,v);
}
else {
if (t[p].rc == 0) t[p].rc = getnew();
Build(t[p].rc,mid+1,r,x,v);
}
t[p].ans = t[t[p].lc].ans+t[t[p].rc].ans;
return;
}
//单点修改位置x为v 动态开点
线段树合并
线段树合并所完成的操作就是:在相同区间内,对应位置相加。
我们可以使用如下方法解决:两个相同区间的节点分别为 p p p和 q q q,合并区间为 [ l , r ] [l,r] [l,r],若未建立则为0.
- 若 p p p和 q q q有其一为0,则另一者为根。
- 若 l = r l=r l=r,则累加权值,返回p。
- 合并 p p p的左孩子和 q q q的左孩子, p p p的右孩子和 q q q的右孩子;再讲对应位置的权值相加,返回 p p p