【做题记录】树上游戏
-
树上游戏
- 算法:点分治、树上差分
题目:
有一棵树,树的每个节点有个颜色。给一个长度为 的颜色序列,定义 为 到 的颜色数量。以及
求所有的 。
题解:
这里有两个算法。一个是 的点分治做法,另一个是 的一个 trick,然后会用到一点的树上差分。这里两种都记了吧。
- 法一:点分治
我本题并不是用点分治过的,所以以下内容仅当作我在口胡。
考虑点分治。对于当前分治到的重心,考虑它自己出发至当前分治子树内的所有路径对答案的贡献,和经过它的路径对当前分治子树内点的贡献。
如果是自己子树内的贡献,可以 dfs 暴力求。
那么来考虑子树外至子树内的路径的贡献。
对于每一棵子树,令 表示从重心到其他子树的路径中包含颜色为
的条数。所以,我们简单 dfs 一下,对于每个子树 ,其贡献为 。
感性理解,每一种颜色 到当前重心 的贡献就为 。然后这个贡献需要下传,所以标记一下。
总的时间复杂度 。
- 法二:奇怪的方法,
虽然是用这种方法的,但还是可能不太清楚,代码部分比较模糊,就仅当口胡吧。
首先,考虑每一种颜色对于答案的贡献。
考虑如果将这种颜色的节点删去的影响。
比如在下图中,我们将绿点删去,那么所有绿点相连的边都会被切断:
那么,此时剩下的点就会变成一个个小子树(链也是子树)。
我们可以得到两个重要性质:
-
在剩下的子树中,若两点在同一子树,那么删去的颜色对它们的
不做贡献; -
若两点在不同子树,那么该颜色必定做出贡献(因为其为两棵子树联系在一起,必有贡献)
所以,正如上面的图三,我们对于剩下的子树全部加上颜色 (这里就是绿色)所带来的贡献。
设 表示对于每种颜色 ,从 出发不包含这种颜色的路径的条数。
设 为颜色总数,那么可得
但是对于每种颜色都要求出删去这种颜色后剩下的子树,时间未免太高。可以考虑差分。将原图中的当前重心的所有子树加上贡献,而再在每一棵子树中存在的以颜色 为重心的子树减去两倍的贡献。
这样就可以 做完了。代码比起上一种好实现得多。
感觉还是讲的不是很透彻,推荐一下这篇 b6e0 的博客,讲得比较好吧。
本文作者:trsins
本文链接:https://www.cnblogs.com/trsins/p/15777656.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步