ことばがありあまれどなお、 このゆめはつづいてく|

trsins

园龄:3年10个月粉丝:18关注:2

【做题记录】树上游戏

  • P2664 树上游戏

    • 算法:点分治、树上差分

题目:

有一棵树,树的每个节点有个颜色。给一个长度为 n 的颜色序列,定义 s(i,j)ij 的颜色数量。以及

sumi=j=1ns(i,j)

求所有的 sumi

1n,ci105

题解:

这里有两个算法。一个是 O(nlogn) 的点分治做法,另一个是 O(n) 的一个 trick,然后会用到一点的树上差分。这里两种都记了吧。

  • 法一:点分治 O(nlogn)

P.S. 我本题并不是用点分治过的,所以以下内容仅当作我在口胡。

考虑点分治。对于当前分治到的重心,考虑它自己出发至当前分治子树内的所有路径对答案的贡献,和经过它的路径对当前分治子树内点的贡献。

如果是自己子树内的贡献,可以 dfs 暴力求。

那么来考虑子树外至子树内的路径的贡献。

对于每一棵子树,令 fci 表示从重心到其他子树的路径中包含颜色为 ci
的条数。所以,我们简单 dfs 一下,对于每个子树 x,其贡献为 ixfci

感性理解,每一种颜色 ci 到当前重心 x 的贡献就为 sizexfci。然后这个贡献需要下传,所以标记一下。

总的时间复杂度 O(nlogn)

  • 法二:奇怪的方法,O(n)

P.S. 虽然是用这种方法的,但还是可能不太清楚,代码部分比较模糊,就仅当口胡吧。

首先,考虑每一种颜色对于答案的贡献。

考虑如果将这种颜色的节点删去的影响。

比如在下图中,我们将绿点删去,那么所有绿点相连的边都会被切断:

111.png

suspect.png

222.png

那么,此时剩下的点就会变成一个个小子树(链也是子树)。

我们可以得到两个重要性质:

  • 在剩下的子树中,若两点在同一子树,那么删去的颜色对它们的 sum
    不做贡献;

  • 若两点在不同子树,那么该颜色必定做出贡献(因为其为两棵子树联系在一起,必有贡献)

所以,正如上面的图三,我们对于剩下的子树全部加上颜色 c(这里就是绿色)所带来的贡献。

fi,c 表示对于每种颜色 c,从 i 出发不包含这种颜色的路径的条数。

col 为颜色总数,那么可得

sumi=j=1col(nfi,j)

但是对于每种颜色都要求出删去这种颜色后剩下的子树,时间未免太高。可以考虑差分。将原图中的当前重心的所有子树加上贡献,而再在每一棵子树中存在的以颜色 c 为重心的子树减去两倍的贡献。

这样就可以 O(n) 做完了。代码比起上一种好实现得多。

感觉还是讲的不是很透彻,推荐一下这篇 b6e0 的博客,讲得比较好吧。

本文作者:trsins

本文链接:https://www.cnblogs.com/trsins/p/15777656.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   trsins  阅读(66)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示