最近想学树链剖分,但无奈,前置技能还不会,
dfs序
还没搞懂是什么玩意,就上B站学习了一波,无奈太菜了,也没听太懂,就了解了个大概,想着去刷道题,练一练,这不,找到了这道 HDU 5692 Snacks,这题真的是好题,费了我不少时间,才搞定, 可能是在家效率太低,可能最近对头发的保养很重视,一天到晚坐在电脑面前学习对目前的我来说是不太可能了。
WA了20来发:
上干货:以这题为例
首先对于这道题我们不难发现,我们要求从
0
点出发,经过点q
,的最大路径和多少,从0点经过点q的点有很多条,即以点q为根,的子节点数量,我们只需要将从0点到所有点的权值和求出来即可眼观得经过点p
的那条路径的权值和最大
未经处理的树形图:
经处理的树形图:
我们先不考虑修改,只考虑询问,这样不就很直观了!但是我们要怎么实现最大值的询问呢,这里dfs序的用处就来了,我们要求的区间,其实就是以p节点和它的所有子节点中哪一个权值最大,而dfs序,其实就是按照dfs的顺序来的,而dfs的性质:一定是把某一节点的根节点询问完后,再跳到另一个节点
以上图为例:
第一种dfs序:0 1 2 3 4 5
第二种dfs序:0 1 2 2 1 3 4 4 5 5 3 0
讲解第一种
假如我要询问经过
1
的区间,这里我们如何询问,其实很简单我们只需要用一个in[]
数组记录每个节点的时间戳,再用一个sizx[]
数组记录以每个节点为根的节点数量大小,然后我们想询问的区间就出来了,是(in[1],in[1]+sizx[1]-1
)
讲解第二种
假如我们还是询问经过1的区间,这里我们可以开一个
in[]
数组记录进入1
的时间戳,再开一个数组out[]
记录离开1的时间戳,这里(in[1],out[1])
就是我们想要询问的区间
注意点:
第二种只有在数据量很小,而且空间时间充足的情况下,使用,不然就会疯狂
TLE,MLE, Runtime Error
,上图WA就是典型,所以最好用第一种
接下来就是线段树的常规操作了
既然我们目前都已经知道要问的区间了,那么不就是一个裸的线段树问题么,相信线段树都会,这里就不讲解了
修改操作
这里的修改涉及区间修改,那么就用一个懒人标记去修改就行了,因为是直接把最初的节点权值变成某值,我们只需要知道他们之间的差值是多少,在一开始处理过的树上进行区间修改就可
AC代码: