CF504E Misha and LCP on Tree
经典套路:哈希+二分,然后还需要述链剖分快速维护对比。
思路好想,代码不好写
代码好难调。。。
这道题我们需要求一条路径的哈希值,需要求出根节点到他的哈希值,还有他到根节点的,然后要写半天。
树上启发式合并
就不讲了,看这道题:
P4149 [IOI 2011] Race
我们发现如果设定合并内容为到当前节点的距离,会很难转移。
所以我们直接存这个点到根节点的长度,然后最后的答案就需要两点的距离减去 LCA 的距离的两倍。
点分治
dsu on tree 是根据子树大小确定最大的子树的贡献直接保留。
而点分治是直接计算重心,用重心进行子树的拆分来完成问题。
这个。
P3806 【模板】点分治
点分治通过每次选取树的重心作为分治点,将树分解为若干子树递归处理,从而高效统计所有经过或不经过当前重心的路径信息。
P6329 【模板】点分树 / 震波
我们通过点分治每次找重心的方式来对原树进行重构。
将每次找到的重心与上一层的重心缔结父子关系,这样就可以形成一棵 层的树。
-
性质 :树是 层的,而且树上所有点的子树大小之和为 ,所以这可以让很多暴力更快。
-
性质 :对于任意两点 ,唯一可以确定的是 在点分树上的 LCA 一定在 的路径上,。(这个感性理解一下,如果 LCA 不在就会出现环)。
然后结合这两个性质我们可以做题了。
这道题的思路
首先我们发现每一对节点的 LCA 个数是 级别的,所以考虑枚举 LCA。
,答案就是拿 的子树内到 的距离 的点权和 方向子树中到 的距离 的点权和。
对每个点 建一棵动态开点线段树,下标为 的位置维护 子树内所有 的 的和。
-
对于 子树内的 ,区间查询即可。
-
对于 在 方向上的儿子 的子树,考虑对于每个点再建立一棵动态开点线段树,线段树上下标为 的位置维护 子树内到 距离 的点权和,然后就可以解决了。
查询:从 沿点分树向上,设当前节点为 ,。若 ,则答案加上 中距离 的和,减去上一节点 的 中距离 的和。
修改:从 沿点分树向上,对每个 , 中下标 增加权值;若 有父亲 ,则 中下标 增加权值。
代码太难调了!!!
线段树合并
就是直接模拟合并。
时间复杂度:每一个节点会被合并一次,然后节点数虽然放到线段树上是 个,但是只会访问这 个中的一个,然后对于每一个节点,会被合并 次(可以尝试势能分析)。
P3521 [POI 2011] ROT-Tree Rotations
P3521 [POI 2011] ROT-Tree Rotations。
思路
我们发现,交换这个点只会改变左右子树间的贡献。
所以我们只需要计算所有点的左右子树间的贡献就行了。
对于每一个点,建一个动态开点权值线段树,线段树的合并就可以计算贡献了,左边 的和右边 的进行这种匹配。
简单总结一下,很多时候都是对于原树的结点,每一个都建立一个权值线段树,维护所有权值,进行合并。然后由于插入的权值数量有限,最后的复杂度也没有问题。
P8496 [NOI2022] 众数
这道题就是直接权值线段树,然后加上二分就行了。
至于删除最后一个数就是链表了。
树形 dp
P4577 [FJOI2018] 领导集团问题
这道题的状态设置成答案为 的时候的最好状态。
然后利用到这道题状态的有序性,直接放入 multiset。
思路
注意:部门不必联通!
表示在 的子树中选择 个点组成的所有树上 LIS 中,级别值 最小值最大的那一个。
然后利用到这道题状态的有序性。
然后我们建立 multiset ,里面的数按升序排列后,第 个数表示: 在 的子树中,选 个结点组成合法集合时,这 个结点中最大的权值最小可能是多少。
然后合并就是直接插入,很好理解。
最后答案就是 multiset 的大小。
长链剖分
P4292 [WC2010] 重建计划
其实这是一道点分治和长链剖分都能做的题。
常见的 trick:二分答案之后,将所有边权减去 mid 然后使最后答案 。
这道题的状态定义和长链剖分的本质密切相关
这道题需要定义一个 表示在 为 的节点上,到他所在的重链底端的权值和。
然后定义 表示 节点向下走 的路劲权值和减去 。
然后这样设计是为了同一条重链上的节点可以直接转移。