题意
给定一棵带边权 { 0, 1} 的无根树,求回文路径的个数。
其中 3 \le n \le 5\times 10^4。
分析
点分治,问题转化为求有多少条过当前重心的路径,使得其构成回文串。
将从重心开始的所有结点对应的串,插入 Trie 树中,最坏情况下 Trie 树与原树同构。
分析跨越重心 root 路径的回文串结构,记两个端点分别为 u,v,其中 u 的深度大于等于 v 的深度。
深度相同,则 root 到 u 路径对应串 (简记为 u 串) 必须等于 root 到 v 路径对应串 (简记为 v 串)。令枚举的每个结点的出现次数为 cnt,这部分答案贡献为 cnt \choose 2。
深度不同,则 v 串等于 u 串的后缀,且 u 串的前缀是一个回文串。
因此,我们考虑对 Trie 树构建 AC 自动机,则 u 串的所有在 Trie 树中有对应结点的后缀就是 fail 树上的所有祖先。注意到,fail 树上的祖先可能很多,无法枚举并检查当前前缀是否为回文串。但是,根据 Border 理论,一个串的回文后缀(前缀)可以表示为 \log n 段等差数列。于是,我们处理所有 Trie 树结点的等差数列 (l,r,d),对应表示首项、末项和公差。这可以在构建完 Trie 树后,dfs Trie 树,并维护正串和反串的哈希值得到。
最后,枚举所有 Trie 树结点,令其深度为 len,再枚举其等差数列,只需要询问 fail 树的祖先上长度为等差数列 (len-r,len-l,d) 的出现次数和,进一步转化可以变成求所有长度 l \equiv ((len-l) \bmod d) ( \bmod d) 的点值和,考虑根号分块容易维护,但是可能会取到一些等差数列值域外的点,可以将询问离线的最大长度上,并拆成两个前缀和,在 dfs fail 树的栈上二分即可获得对应结点。
总结
点分治。
插入从重心开始的 Trie 树。
dfs Trie 树,求出每个点回文前缀的等差数列。
dfs fail 树,维护栈上的结点,维护栈上支持快速查询模 b 余 r 处点值的分块数据结构。枚举等差数列,对于公差小的,栈上二分找到询问离线点,对于公差大的,暴力枚举。
枚举 Trie 树结点,计算回文前缀为空和不为空的匹配方案数。
点分治容斥掉来自同一子树的配对答案数。
时间复杂度:T(n)=2T({n \over 2})+O(n \sqrt{n}+n\log^2 n),T(n)=O(n \sqrt{n})。