2 条题解
-
0
题解
方向
先考虑根节点固定。
显然,代价为:
$$Ans = \sum _{(u,v)为轻边,且u为v的父节点} siz_{u} * ( n - siz_{u} )$$设:
$$B = \sum _{(u,v)为重边,且u为v的父节点} siz_{u} * ( n - siz_{u} )$$答案转化为:
由于 是与根无关的常数( 关于根对称),最小化 等价于最大化 。
最大化
树链剖分等价于每个结点独立地从儿子中选一个"重儿子"。因此:
$$B = \sum_{u} \max_{v\in sons(u)} siz_{v}*(n-siz_{v})$$每个结点的选择互不影响,所以每个结点贪心取 最大的儿子当重儿子即可。
注意:这里每条边的 与根无关,故只需用任意根 DFS 一次求出每条边的固定权值 。
换根
从根 换到相邻点 时,只有这两点的"候选儿子集合"改变:
- 由非根变根,候选集合多出边 ;
- 由根变非根,候选集合去掉边 ;
- 其余结点的父子方向不变。
所以只需把权值 从 的集合移到 的集合,更新这两点对 的贡献即可。用
multiset维护每个结点候选儿子权值的最大值,单次增删、取最大值均为 。复杂度
- 每次换根只移动一条边,进入/回溯各一次,。
- 每个结点作为根被处理一次,总复杂度 ,可过 。
- 权值最大约 ,需用
long long。
代码
数据结构
g[u]:邻接表,存 。cur[u]:multiset,存"以当前根为根时, 的所有儿子边权值",用其最大值贡献到 。sz, fa:任意根 DFS 求出的子树大小与父节点,用来给每条边定向并算 。W, B, ans:总重边无关常数、当前根的重边贡献和、答案数组。
整体流程
-
预处理:以 为根 DFS,得到
fa和sz。对每条边算固定权值 ,累加得到 。 -
初始化根 :把每条边放入其"父节点"的
cur中,即cur[fa[i]].insert(w)。于是每个非根点的cur刚好是它以 为根时的全部儿子边。累加每个点的max(cur[u])得到 ,则ans[1]=W-B。 -
换根(核心):写递归函数
rtt(u, from),表示当前根为 。对 的每个邻居 :- 把边权 从
cur[u]移到 `cur[v]$; - 用
max前后差值更新 (只有 两点贡献变化); - 记录
ans[v]=W-B;递归rtt(v,u); - 回溯时逆操作把 移回,恢复 。
- 把边权 从
信息
- ID
- 2786
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 7
- 标签
- (无)
- 递交数
- 10
- 已通过
- 5
- 上传者