我们先来看这么个题:
给你一棵树,每次可能修改一条路径上的值,或是修改一整棵子树上的值,现在有多次查询,要查询一条链上的最大值(或是和),或是查询一棵子树上的最大值(或是和)。模板题,我们考虑最暴力的做法,对于每一条链,求LCA,然后暴力修改,这不用想就知道绝对要凉。那么我们想一想,如果我们维护的不是一棵树,而是一个链,那么我们有很多种方法来维护了(线段树,树状数组,主席树,分块等等等等),那么我们是不是只要把一棵树变成一条链就可以了?
那么我们考虑最简单的变法:$dfs$序。具体的操作我们发现有很多种,这里介绍最简单的一种(除了这种其他都不会系列)叫轻重边剖分。那么我们先来搞个定义:对于树上的每一个节点,$size_i$表示i号节点的子树大小,那么我们在定义对于一个节点的所有子树,$size$最大的儿子就是这个节点的重儿子,另外的都是轻儿子,连接重儿子和父亲的边叫重边,其余的叫轻边,由多条重边组成的路径就叫重路径。
直观的就是下图:
嗯,好,那么接下来的事就很简单了:我们对整棵树进行dfs,优先扫重边。这样的话一条重链上的点的dfn就是连续的,所以我们对重链就可以快速修改了:对于每一条路径,我们可以将其拆分成多条重链和多条轻边,对于轻边,我们无视,应为轻边的两端一定是重链(特殊的,一个点也算重链),所以,我们可以采用LCA的方式,每一次找出重链的顶点,然后逐层上推,知道两点会和。具体的看我代码吧(自认为还是非常清楚地)
1 |
|