线段树合并
概述
线段树的合并是线段树的常用技巧,常见于权值线段树维护可重集的场景。
例如,树上某些结点处有若干操作,如果需要自下而上地将子节点信息传递给亲节点,而单个结点处的信息又方便用线段树维护时,就可以应用线段树合并的技巧控制整体的复杂度。
适用范围
其实线段树合并适用范围很广,要求两颗线段树形态相同,且维护信息可以合并(如 \(sum,max\))。
但一般用于动态开点权值线段树合并,因为两颗节点开满的线段树合并复杂度是 \(O(n)\) 的。
实现
int merge(int x,int y,int L,int R){
if(!x||!y)return (x|y);
if(L==R){ sum[x]+=sum[y]; return x; }
int mid=(L+R)>>1; push_down(x),push_down(y);
lch[x]=merge(lch[x],lch[y],L,mid);
rch[x]=merge(rch[x],rch[y],mid+1,R);
push_up(x); return x;
}
复杂度
动态开点权值线段树合并。
设值域为 \(W\),共有 \(n\) 个权值,则合并总复杂度为 \(O(nlogW)\)。
证明:
设两棵线段树为 \(T_x\) 与 \(T_y\),设其共开有 \(sum_x\) 和 \(sum_y\) 个节点。
设最终线段树为 \(T_z\),设合并访问节点数有 \(sum_z\) 个。
\[引理1:若存在节点c在T_x而不在T_y中,则sum_x+sum_y<sum_z
\]
\[引理2:若T_x与T_y形态相同,则sum_x+sum_y=sum_z
\]
综合引理1与引理2可知:形态形同的线段树可以将访问次数卡满。
那么我们考虑最坏的情况:\(n\) 棵线段树开点形态完全形同。
这样相当于合并 \(n\) 条有 \(logW\) 个节点的链,总共访问 \(nlogW\) 次。
综上,动态开点权值线段树合并的复杂度为 \(nlogW\)。
树上合并
权值线段树本质上就是维护了一个可重集。
树上合并不只有树上启发式合并,还有线段树合并。
结语
线段树合并只是一种技巧,线段树合并的题还是要从线段树本身思考。

浙公网安备 33010602011771号