[复习资料]一类简单的树上找最小连通块问题
一类简单的树上找最小连通块问题
问题描述
给定一棵 \(n\) 个点的树,边有边权,再给定若干个关键点,求最小的包含所有关键点的连通块的边权和。
解决方法
直接讲结论吧,首先 \(\rm dfs\) 得出树上所有点的 \(\rm dfs\) 序,不妨设将所有关键点按 \(\rm dfs\) 序排序后得到的序列为 \(a_1,a_2,\dots,a_m\) ,那么答案就是 \((\operatorname{dist}(a_1,a_2)+\operatorname{dist}(a_2,a_3)+\cdots+\operatorname{dist}(a_{m-1},a_m)+\operatorname{dist}(a_{m},a_1))/2\) 。
为什么是这样的?考虑一条边的边权何时会被算入答案,当且仅当这条边的两边都存在关键点,如下图:
在计算路径的时候,我们从下往上计算了这条边的边权一次,从上往下又计算了一次,所以除以二就是答案。
如果这条边不应该被算入答案,那么显然就不会被算入答案。
其他扩展问题
一、给定一棵 \(n\) 个点的树,点有点权,再给定若干个关键点,求最小的包含所有关键点的连通块的点权和。
解决方法:把点权上放到边权,然后唯一没有计算到的点权就是最上面的那个点的点权,直接加上去就行了。
二、给定一棵 \(n\) 个点的树,边有边权,再给定若干个关键点,然后给最小的包含所有关键点的连通块的所有边的边权加一。
解决方法:之前讲的是求和,这里变成了修改,其实都是一样的,通过上面按 \(\rm dfs\) 排序的处理之后,都转化成了路径求和和路径修改,如果是静态的可以树上差分做,如果是动态的差分后树状数组,树链剖分和 \(\rm LCT\) 都可以维护。
三、给定一棵 \(n\) 个点的树,边有边权,再给定一个关键点集合,需要实现加入删除点和求最小的包含所有关键点的连通块的边权和。
解决方法:使用一个 \(\rm set\) 维护这个关键点集合,然后每次插入一个点 \(w\) 就找到 \(\rm dfs\) 序小于该点的第一个点 \(u\) (如果没有就是 \(\rm dfs\) 序最大的点)和 \(\rm dfs\) 序大于该点的第一个点 \(v\) (如果没有就是 \(\rm dfs\) 序最小的点),然后相当于是去掉路径 \(u,v\) 的贡献,加上 \(u,w\) 和 \(w,v\) 的贡献。
和字符串算法的结合
其实我写这篇文章就是为了讲这个的。
考虑这样一个问题:给定若干模式串和若干匹配串,求每个模式串在所有匹配串中的出现次数。
显然可以使用 \(\rm AC\) 自动机来做,将模式串建立 \(\rm AC\) 自动机,然后把所有匹配串丢到自动机里面去跑,每到达一个节点就在 \(\rm fail\) 树上面进行根节点到当前点的链上加一操作,最后每个模式串对应节点的点权就是这个模式串的答案。
对于链上加操作,如果是静态的可以树上差分,如果是动态的可以用树链剖分或差分后树状数组线段树做。
换一个问题:给定若干模式串和若干匹配串,求每个模式串在多少个匹配串中出现过。
如果仅有一个匹配串,可以求出 \(\rm AC\) 自动机上面对应的所有字符串的出现次数,如果次数大于 \(0\) 那么就表示这个字符串在模式串中出现过。
如果有多个匹配串,显然不可以对每个模式串都进行一遍判断出现次数是否大于 \(0\) 的操作,因为做一次这样操作的复杂度是 \(\mathcal O(\text{AC自动机节点个数})\) 的,显然不太优美。
还有一种方法,就是每次走到新的一个节点,并不是直接链上加,而是一直往上找到没有被遍历过的点,然后再进行加和,实现过程如果使用二分加树剖的话,恐怕是 \(\mathcal O(\log_2^3n)\) 的,不推荐,如果是暴力跳 \(\rm fail\) 指针,复杂度可能就是假的了。
我们发现,最终出现在匹配串中的字符串,其实就是 \(\rm fail\) 树上所有遍历过的点到根的路径的并,其实就是我们一开始讨论的问题,如果把这些遍历过的点和根节点看做是关键点,那么我们要实现的其实就是最小包含所有关键点连通块修改,于是就可以转化为路径修改。
这样做的复杂度是正确的,而且使用差分后时间复杂度就只带了一个 \(\log\) 。
再考虑另外一个问题:给定 \(n\) 个字符串和一个数集 \(S\) ,如果一个字符串仅在 \(n\) 个字符串中的 \(x\) 个字符串中出现过,并且 \(x\in S\) ,那么我们称这个字符串是“Imakf喜爱的”,请对于每个字符串它有多少个本质不同的子串是“Imakf喜爱的”。
由于是子串,所以我们先建立广义 \(\rm SAM\) ,接下来的问题就是求出 \(\rm SAM\) 上面每个节点对应字符串在哪些字符串里面出现过,和 \(\rm AC\) 自动机一样的,不过这次是在 \(\rm parent\) 树而不是 \(\rm fail\) 树上面实现连通块修改操作,然后处理完后再判断一下这个字符串是不是“Imakf喜爱的”,接下来的问题就是对于每个字符串找到其所有的“本质不同的子串”对应的节点,也就是连通块求和操作,码量可能有点大。
例题
一些简单的字符串题目:
SP8093 JZPGYZ - Sevenk Love Oimaster
SAM 的题目好像没有找到呜呜呜,如果找了类似的题目可以在评论区提醒我一下,谢谢。