2 条题解
-
10
树链剖分(decomposition)
定义一个树的一种树链剖分的权值为:所有 之间的经过轻边的个数的和。
定义一个树的最优树链剖分为权值最小的树链剖分。
给定 个点的树。
对于每一个节点 ,求以 为根的情况下的最优树链剖分的权值。
。
显然的换根 DP,于是我们先考虑单次树形 DP 怎么求。
首先我们应该拆贡献:对于每一条边 ,其中 是 的父亲,那么共有 个路径经过它。那么只要其不是重边,答案就要累加这个值。
于是我们定义 表示考虑 子树内的所有边的贡献的最小权值,则有:
$$f_x=\sum_u f_u+\sum_u sz_u(n-sz_u)-\max_u\{sz_u(n-sz_u\}$$设 表示 子树内最大次大的 。同时定义 为达到 的儿子。
直接模拟可以做到 。
然后就是换根 DP(多画图,不然很可能看不懂下面的)。
不妨设 表示以 为根时的 DP 值,且我们现在要从 转移到 。
那么 应该分为 个部分:
- ,因为 可以变化,通过 这条边进行更新。
- ,这里就是利用 这条边更新。注意,这次的通过父节点的更新应该永久的带到 的子树中,因为以 子树为根时依然有 这条边。
- ,因为要加上 这条边的贡献。
- :要加上 的贡献。同时 需要去掉 这一部分。并且,由于去掉了 子树, 可能更新。
- $-\begin{cases}d_{1,x}& D_{1,x}\ne u\\d_{2,x}&D_{1,x}=u\end{cases}$。
然后模拟即可 。
-
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); - 回溯时逆操作把 移回,恢复 。
- 把边权 从
- 1
信息
- ID
- 2786
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 7
- 标签
- (无)
- 递交数
- 10
- 已通过
- 5
- 上传者