树链剖分的一种用法

这篇文章好像发得有点迟了啊QAQ之前忘了发了

又好久没更了,讲一个提高组内容。

我们来考虑一个有趣的问题,我们有一棵有根树,每个点有点权,要求支持单点加,子树加。

询问比较奇怪,每个点有一个点权x,假装不变,每次询问指定一个点p,对于它的每个孩子(直系的)s,将x[s]*s的子树和相加输出。

先假装没有子树加,考虑直接用树链剖分来做这个东西。那么我们询问某个点的孩子的时候,我们发现有两种孩子,一种是重孩子,一种是轻孩子。

对于重孩子,因为只有一个,所以我们可以直接在dfs序上搞一个树状数组统计。

如果是轻孩子?考虑一个被计入答案的点,那么这个轻孩子肯定是这个点的祖先,而且是某条重链的顶端。我们可以在单点加的时候暴力跳它往上的重链,跳到某重链顶端时更新顶端的父亲的答案,然后继续跳。考虑到重链剖分的复杂度,这样做是一个log的。

接下来我们考虑子树加怎么做。假设我们询问a的子树,子树b之前进行了一次子树加。如果a和b子树不交显然对答案没有影响。如果a是b的祖先(不包括b),那么我们可以把b整棵子树当成一个点,像上面那样跳重链更新答案。如果b是a的祖先(包括a),那么a子树的每个点都受到了影响,我们只要把a的轻儿子的x相加乘上计入贡献即可,这个可以用两遍dfs序来实现。

用类似的方法可以支持点权修改和询问子树dp值。如果dp值比较复杂,还可以考虑使用线段树维护每个点的子树。

posted @ 2017-05-18 16:03 fjzzq2002 阅读(...) 评论(...) 编辑 收藏