树链剖分
在处理一类在树上修改,查询的问题时,我们往往需要把这棵树剖分成一个序列。然后利用数据结构在这个序列上把你所需要的东西一段一段地查出来。但如果剖分方法不得当的话,每一次查询就可能只查询了一个点,时间复杂度还不如暴搜!因此我们需要一个优秀的算法来帮助我们进行剖分,这就是树链剖分(启发式剖分,轻重链剖分)。
我们把每一个点最大的儿子叫做重儿子,其余的叫做轻儿子。连接重儿子的叫做重边,其余的叫做轻边。由重边组成的链叫做重链,由轻边组成的链叫做轻链。然后对于每一条重链,它上面的点在线段树里的编号都是连续的。这样就能解决问题了(因为我们保证了一个树上路径被分成了尽量少块)。
现在来讲讲怎么打。
对于每一个点x,我们用top[x]表示它所在的重链的顶端节点,fa[x]表示它的父亲,w[x]表示它在线段树中的位置(用来修改),size[x]表示以它为根的子树的大小(用来求son),son[x]表示它的重儿子,d[x]表示它的深度。这些东西可以用两遍dfs求出。
然后对于询问x,y。我们设f1=top[x],f2=top[y],然后查找w[f1]到w[x]的答案,并把x=fa[f1],f1=top[x]。然后每一次如果d[f1]< d[f2]就把x和y,f1和f2交换(方便计算,我有点懒)。最后再把x到y的答案统计一下就行了。