『ZJOI2019 D2T2』语言

~~ 话说,本题考场想出三只\(log\)的暴力做法,被卡成暴力了。~~

题目分析

首先考虑枚举每一个点,计算这个点可以和多少点进行交易。

将所有经过该点的路径\(s,t\)拿出,那么这些极远的\(s,t\)构成的连通块大小\(sz - 1\)就是答案。

\(Codeforces\)\(异象石\)那题可以想到,若一些点集按照\(dfs\)序排序,那么这些点构成连通块大小就是

\(\frac{1}{2} (dist(a_1 , a_2) + dist(a_2,a_3) + ... + dist(a_{k-1} , a_k) + dist(a_k,a_1))\)

考虑对于每一个节点开一棵线段树,其叶子节点\(i\)表示\(dfs\)序为\(i\)的极远点出现次数。

线段树中存储\(3\)个值\(lp,rp,Sum\)分别表示当前存在的大于\(0\)的最小下标和最大下标,和不算头尾的连通块大小。

由于路径条数为\(m\),显然我们可以用可持久化线段树来维护这\(n\)棵线段树,使得空间复杂度为\(O(m log_2 n)\)

利用树上差分的思想,对于每一条\(s,t\)的路径,我们先在\(s\)\(t\)所在的线段树中将\(dfn[s]\)\(dfn[t]\)两个点单点\(+1\)

然后在\(father(lca(s,t))\)的节点,将\(dfn[s]\)\(dfn[t]\)两个点单点\(-2\)

于是,我们可以自下往上去统计每个节点的答案。

每一次,我们需要对该节点的所有子树进行线段树合并,然后询问这个节点的答案,将其累加进总个数中。

这样,我们就完成了无序数对的统计,那么此时答案除以\(2\)就是最终的答案。

复杂度分析

由于\(n\)次线段树合并节点总数是\(m\)个,所以需要时间复杂度为\(O(m log_2 n)\)

由于\(m\)次线段单点修改,使用\(O(1)\)\(LCA\)实现,所以需要时间复杂度为\(O(m log_2 n)\)

所以,本题的总时间复杂度就是\(O(m log_2 n)\)

你可能感兴趣的:(『ZJOI2019 D2T2』语言)