hdu7219

题面

给定一颗带点权的树,求点权和最大的且直径不超过 \(k\) 的联通块权值和。

数据范围:\(k\le n\le 10^5\)

题解

首先有dp,设 \(f_{x,i}\) 表示 连通块最高点是 \(x\) ,此时最深的点到 \(x\) 的距离不超过 \(i\) 的最大权值和,有转移:

  • \(i+i\le k\) ,此时 \(f_{x,i}=f_{x,i}'+f_{y,i}\)
  • \(i+i> k\) ,此时 \(f_{x,i}=\max(f_{x,i-1},f_{x,i}'+f_{y,k-i},f_{x,k-i}'+f_{y,i})\)

现在要考虑优化这个转移。

注意到 \(f_{x,i}\) 是关于深度的,所以可以长链剖分优化,但是这个长链剖分只能做第一部分,第二部分就G了。

准确的说,是只有第一部分的形式是可以直接转移的。

因为要保证长链剖分的复杂度,我们把 \(y\) 合并到 \(x\) 上,是需要一个关于 \(O(len_y)\) 的算法的,\(len_y\)\(y\) 这条长链的长度,也就是说,如果 \(len_y<k/2\) ,那么对于 \(f_{x,i}\) ,其中 \(i\in[k/2,k-len_y]\) ,都需要区间加上 \(f_{y,len_y}\)

再考虑第二部分,我们发现需要做第二部分转移的个数只有 \(\min(len_y,k/2)\) 次,所以我们是可以暴力去做的。

之后还需要处理一个问题,就是当计算上 \(val_x\) 之后,会让 \(f_x\) 的一段前缀 \(<0\) ,这时候我们就需要把这些部分变成 \(0\)

所以就需要一个支持 单点加、区间加、给一段前缀赋值 的东西,这很显然需要一个线段树。

注意为什么我们不能在合并 \(x,y\) 的时候把 \(y\) 的值与 \(0\)\(\max\) ,而需要即时修改,因为 \(x\) 的父亲是直接继承 \(x\) 的值的,所以这些负数会影响 \(x\) 父亲的合并,所以线段树是不可少的。

上面的转移看起来比较小清新,但是实际上实现的时候细节巨多,调吐了。

启发

  • 长链剖分只是一种父亲直接继承重儿子,与其他链合并时需要做到关于 \(O(len_y)\) 的一种思想,所以内部的实现也是可以加数据结构的。
posted @ 2022-08-11 23:04  qwq_123  阅读(38)  评论(0编辑  收藏  举报