树链剖分 + 树上差分 + 线段树合并
Description
九条可怜是一个喜欢规律的女孩子。按照规律,第二题应该是一道和数据结构有关的题。
在一个遥远的国度,有 $n$ 个城市。城市之间有 $n − 1$条双向道路,这些道路保证了任何两个城市之间都能直接或者间接地到达。
在上古时代,这 $n$ 个城市之间处于战争状态。在高度闭塞的环境中,每个城市都发展出了自己的语言。而在王国统一之后,语言不通给王国的发展带来了极大的阻碍。为了改善这种情况,国王下令设计了 $m$ 种通用语,并进行了 $m$ 次语言统一工作。在第 $i$ 次统一工作中,一名大臣从城市 $s_i$ 出发,沿着最短的路径走到了 $t_i$
,教会了沿途所有城市(包括 $s_i, t_i$) 使用第 $i$ 个通用语。
一旦有了共通的语言,那么城市之间就可以开展贸易活动了。两个城市 $u_i, v_i$ 之间可以开展贸易活动当且仅当存在一种通用语 $L$ 满足 $u_i$ 到 $v_i$ 最短路上的所有城市(包括 $u_i, v_i$),都会使用 $L$.
为了衡量语言统一工作的效果,国王想让你计算有多少对城市 $(u, v)\ (u < v)$ ,他们之间可以开展贸易活动。
Samples
Input #1
1 | 5 3 |
Output #1
1 | 8 |
Explanation
可以开展贸易活动的城市对为 $(1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4), (3, 5)$
Solution
首先, 如果两个城市$u, v$能够开展贸易, 我们称”$u$能到达$v$”或”$v$能到达$u$”.
考虑维护维护每个节点能到达的节点集合$S_u$, 显然答案是$\frac {\sum_{i=1}^n S_i}{2}$(因为这里没有保证$u < v$)
将树树剖, 这样把每一次修改的路径拆成了不超过$\log n$个区间, 如果对每一个节点的$S_u$都直接用线段树维护, 那么就需要把每个节点跑一遍$\log n$的区间覆盖, 总复杂度$\mathcal O(n^2 \log^2 n)$, 可以得到暴力分的好成绩.
容易发现, 我们现在需要做的是对树上一条路径$u \to v$的推平, 首先讨论的求出$k = \rm{lca(} u, v \rm{)}$ , 那么等同于推平$u \to k$, $k \to v$两条链.
链上修改就可以很显然的转化为树上差分打标记, 分别给$u, v, k, fa[k]$ 打上 $1, 1, -1, -1$ 的标记.
然后因为每个节点$u$需要用到它的儿子的信息, 而我们又不能直接开$n$棵线段树, 那么就可以用线段树合并来完成.
注意: 因为这里是差分, 所以区间覆盖会变成区间加, 写的时候要注意一下.
Code
1 | /* Headers */ |