线段树合并
线段树合并
用一个新的线段树(也可是原先中的一个)包含两个原线段树的信息便是线段树的合并。
由于基础的线段树son为i*2和i*2+1需4倍空间且下标无法改变的缺点,在需合并的情况下就要使用动态开点线段树。
动态开点线段树
多开一个数组son[N][2]记录每个点的儿子位置。(其实真的很简单:)
void build(int L,int R,int l,int r,int now) { if(l==r) { t[now]=a[l]; return; } int m=l+r>>1; if(L<m) son[now][0]=++tot,build(L,R,l,mid,tot); if(R>m) son[now][1]=++tot,build(L,R,mid,r,tot); pushup(now); }
合并
两树维护的内容需具有可合并性才可合并,如区间和、区间最值都可以。
b树合并到a上,同时对两棵树做dfs,如果发现其中一棵缺少当前节点,就把另一棵树的连上去,否则按照规则合并。
是哪棵合并到另一棵上就取决于最后return的是哪棵数的点了。
普通线段树
两数组相加,区间和
int merge(int now1,int now2)///将2号树合并到1号上 { if(!now1||!now2)return now1+now2; t[1][now1]+=t[2][now2]; son[now1][0]=merge(son[now1][0],son[now2][0]); son[now2][0]=merge(son[now2][0],son[now2][0]); return now1; }
两数组相加,线段树维护区间最大值和最大值下标
int merge(int now1,int now2,int l,int r)///将2号树合并到1号上 { if(!now1||!now2)return now1+now2; if(l==r) t[now1].x+=t[now2].x; int m=l+r>>1; son[now1][0]=merge(son[now1][0],son[now2][0],l,m); son[now1][1]=merge(son[now1][1],son[now2][2],m+1,r); pushup(now1); return now1; }
权值线段树
int merge(int x,int y,int l,int r) {
if(!x||!y)return x+y; if(l==r){t[x].v=t[x].v+t[y].v;return x;} int mid=l+r>>1; t[x].l=merge(t[x].l,t[y].l,l,mid); t[x].r=merge(t[x].r,t[y].r,mid+1,r); pushup(x); return x; }