[CTSC2010]珠宝商

题目描述

题解

首先我们考虑一种做法,对于一棵树考虑枚举每个点为根去 $ ext{dfs}$ ,然后建立出特征串的 $ ext{SAM}$ ,每次走到的点计算 $ ext{right}$ 集合大小即可。效率为 $O(size^2)$ 。

考虑另一种做法,我们可以点分治,考虑 $u→x→v$ 这一条路径,我们可以考虑 $u→x$ 在特征串中的结尾位置打上标记, $x→v$ 在特征串中的开头位置打上标记,然后每个位置左右标记相乘即可。具体的方法为建立前缀树和后缀树,然后边 $ ext{dfs}$ 的时候边打标记,最后再走一遍前缀树和后缀树,记录对应点的祖先的标记总和即可,记得容斥掉同一棵子树的贡献。效率为 $O(nm+nlogn)$ 。

我们考虑将这两个暴力合并起来,即我们设定一个 $B$ ,对于 $size le B$ 的子树我们直接做第一个暴力然后返回即可,这样的子树至多有 $frac{n}{B}$ 个,所以效率为 $O(frac{n}{B}B^2)=O(nB)$ 。

对于 $size>B$ 的子树,根据点分治的性质,每个点分中心的子节点的子树的 $size$ 大小不会超过其一半,最坏情况是每次合并两个子树,由于最底层的子树大小是 $>B$ 的,而二叉树的节点数大约是叶子结点数的 $2$ 倍,所以这样的子树是 $O(frac{n}{B})$ 级别的,每次的效率为 $O(m+size)$ , $size$ 我们可以忽略掉,所以效率为 $O(frac{n}{B}m)$ 。

因此我们平衡规划一下,即当 $B=sqrt m$ 的时候效率最优为 $O((n+m)sqrt m)$ 。

代码先咕咕咕啦

原文地址:https://www.cnblogs.com/xjqxjq/p/12444926.html