CF601D Acyclic Organic Compounds

洛谷 CF

  • 给出一棵 \(n\) 个点的有根树,每个点上有一个字符 \(s_i\) 和权值 \(c_i\)

  • 定义 \(str(u,v)\)\(u\)\(v\) 路径上所有点上的字符顺次拼接得到的字符串。

  • 定义 \(\text{dif}(u)\) 为在 \(u\) 子树内任选一个点 \(v\),可以得到多少种本质不同的 \(str(u,v)\)

  • \(\max\limits_{i=1}^n (\text{dif}(u)+c_u)\),以及多少个点取到最大值。

  • \(n\le 3\times 10^5\)

首先本质不同的 \(str(u,v)\) 等价于本质不同的 \(str(v,u)\)。考虑树上启发式合并,用 std::set 维护每个子树内有多少种本质不同的哈希值。

但是这题又不太一样,因为每个点继承重儿子时,重儿子内的所有 \(str(v,u)\) 都要拼上当前点的字符,因此哈希值需要整体乘 / 加。

考虑维护 \(mul,add\) 两个标记,表示 std::set 里的元素要乘上 \(mul\),再加上 \(add\) 才能得到真实值。那么我们 std::set 里维护的值,就是与标记运算后能得到真实值的数(称为 \(base\))。那么有几种真实值,就是有几种 \(base\)。遍历轻儿子子树插入 \(base\) 就可以得到当前子树的 std::set

由于轻儿子子树内的点是不需要与 \(tag\) 运算的,因此它们的 \(base\) 就是要“撤销”标记,再与标记运算,相当于不变,即真实值。所以还需要求出 \(mul\) 的逆元来撤销。

还要注意标记的合并,比如我先乘 \(a\)\(b\),再乘 \(c\)\(d\),那么对于一个数 \(x\) 而言,它会变成 \(c(ax+b)+d=acx+bc+d\),此时 \(mul\) 变成 \(ac\)\(add\) 变成 \(bc+d\)

时间复杂度为 \(\mathcal{O}(n\log^2 n)\)(应该可以用哈希表做到 \(\mathcal{O}(n\log n)\)),空间复杂度为 \(\mathcal{O}(n)\)。注意要写双哈希。

提交记录(含代码)

posted @ 2023-11-05 09:59  lzyqwq  阅读(17)  评论(0)    收藏  举报