dsu on tree
作者:互联网
子树类查询问题
dsu on tree和长链剖分都是解决子树类静态查询问题的统计类算法。
这类问题首先要是“子树”查询,并且是“静态”不带修改的。
注意某些问题其实不太有必要上dsu on tree,比如子树元素和,子树元素最大值之类的。(可合并区间信息)
例如子树众数,子树元素种类数这些不可合并区间信息的问题适合dsu on tree
dsu on tree和长链剖分可以解决的场景与线段树合并的场景很多情况是相同的,但实际上线段树合并并不难学。
我是建议都学的,然后在真正的使用过程中,dsu on tree与长链剖的常数更小。
如果你都会的话,并且线段树合并与dsu on tree长链剖都能解决问题,我建议你选后者,避免被卡常。
我们先复习一下,在不使用dsu on tree的情况下如何解决子树类区间问题。
*借助dfs序列,将树映射到数组区间。
然后可以使用各种各样线性序列中的数据结构和算法。
比如莫队,线段树。
dsu on tree
dsu on tree这个算法的本质是“优雅的暴力”,也就是在思想上这个算法和莫队更接近一些。
但是在复杂度证明和原理上,它更偏向于轻重树链剖分。
当然它还要一些别名,比如“树上启发式合并”、“轻重树链分治”等。
前提
既然思想上这个算法和莫队相同,我们这里先复习一下莫队的思路
假定现在有一个数组a,数组里面有若干个元素,然后你已知[l1,r1]这段区间的区间和,假设区间[l1,r1]与区间[l2,r2]有大面积重合
重合率达到90%。问你如何在已知[l1,r1]区间和的情况下计算[l2,r2]的区间和?
那么只要把原本的lr端点向右移动到下一个查询的位置,然后移动的时候把需要维护的信息加入或者删除。这样就节约了计算它们公共部分的时间复杂度。
那么任意两个相邻查询之间就能节约出一个“公共子问题大小”的时间复杂度。
我们想一下子树问题中是否存在这种“公共子问题”。
我们发现对于子树类查询问题,当且仅当两个查询的子树根节点x,y存在祖先关系时,它们存在“重复子问题”,并且子问题重复率是100%。
简单来说,子树问题就两种情况,包含或分离
比如上图,4节点的子树就包含在2节点内,2节点的子树与3节点的子树之间是分离关系
具体分析
先给你这么一棵树,根节点是1号节点有n-1条有向边链接,假设每个点有点权,第i个点的权值为val[i]。
我进行若干次查询,每次查询以某点为根所表示的子树权值和。
假设我是这样暴力统计子树和的。
我要查询节点{1,4}的权值和,在不改变算法的情况下,如何降低复杂度?
那无非就是两种查询的顺序。
1、先查1再查4
2、先查4再查1
那显然是先查4再查1,复杂度更优。
因为4是1的子问题,但是反过来并不是。
先查1再查4的过程:
dfs(1);
init();
dfs(4);
先查4再查1的过程:
dfs(4);
dfs(1);
现在引入一个新的问题:
假设我全查了,如何安排顺序使得复杂度最小化(假设init函数不消耗时间)?
dfs(5);dfs(3);init();
dfs(7);init();
dfs(6);dfs(4);dfs(2);dfs(1);
那这个所谓的“最优求解顺序”是怎么来的呢。
对于一个树的子树情况,无非就两种情况,我们不妨分情况讨论。(这里其实还有叶节点的情况,但是叶节点没孩子嘛,所以不用考虑)
1、单链
2、分叉
单链是最简单的,只要按照dfs(n),dfs(n-1)....dfs(1)的顺序执行即可
标签:子树,dsu,tree,dfs,查询,节点 来源: https://www.cnblogs.com/hh--boke/p/16475724.html