九省联考 2018 秘密袭击
题意
给定一颗含 $n$ 个结点的树,每个点有点权 $d_i$ ,求所有联通块中第 $k$ 大之和。
$1\leq n,m,k\leq 1666,1\leq d_i\leq m$ ,时间限制 $5$ 秒。
题解
一道很有趣的题目。
做法简述:由于 $dp$ 为卷积形式对其多项式求点值,并通过类似整体 $dp$ 的方式维护变换,再通过拉格朗日插值还原多项式。
由于每次统计 $d_i$ 较难,一个直观的想法是转化成 $0/1$ 问题,若答案为 $d_i$ ,则在 $[1,d_i]$ 均统计一遍。
具体的,答案可以写成 $\sum_{S} kth(S)=\sum_{S} \sum_{i=1}^n [i\leq kth(S)]=\sum_{i=1}^n \sum_S [i\leq kth(S)]$ 。
那么对于每个 $i$ ,将点权 $\geq i$ 的设为 $1$ ,其余为 $0$ ,那么我们只需要知道有多少个联通块其点权和 $\geq k$ 。
这是一个简单的树形 $dp$ ,根据树形背包可得时间复杂度为 $\mathcal O(nkw)$ 。
据说就过了此题???喜提 $\text{LOJ}$ 最优解,比我的快 $20$ 倍(
我们将 $dp$ 式子写出,设 $f_{i,j,p}$ 表示当前根为 $i$ ,且考虑点权 $\geq j$ 的情况时选择 $p$ 个 $1$ 的联通块个数。
也很好转移
$$
f_{i,j,p}=\prod_{(u,v)} (f_{v,j,c_v}+1) (\sum c_v=p-[d_i\geq j])
$$
由于背包的实质为卷积,不妨将该 $dp$ 写成 $\text{OGF}$ 的形式。
设
$$
\begin{aligned}
F_{i,j}&=\sum_{p=0}^n f_{i,j,p}\cdot x^p\\G_{i,j}&=\sum_{v\in sub(i)}^n f_{v,j}
\end{aligned}
$$
可得
$$
\begin{aligned}
F_{i,j}&=x^{[d_i\geq j]}\prod_{(u,v)} (F_{v,j}+1)\\Ans&=\sum_{i=1}^{m} \sum_{j=k}^m [x^j] G_{1,i}\\&=\sum_{j=k}^m[x^j] \sum_{i=1}^m G(1,i)
\end{aligned}
$$
显然这东西不能跑过去。
考虑进一步的优化,由于多项式乘法太慢我们不妨求出 $\sum_{i=1}^m G(1,i)$ 多项式的点值最后在通过拉格朗日插值插回去,那么我们需要求出 $n+1$ 个点值。
显然
$$
\begin{aligned}
F_{i,j}(x)&=x^{[d_i\geq j]} \prod_{(u,v)} F_{v,j} (x)\\G_{i,j} (x)&=\sum_{(u,v)} G_{v,j} (x)+F_{i,j} (x)
\end{aligned}
$$
但这还是 $O(nkw)$ 的。(悲
先考虑 $x$ 为定值且仅有一个的情况。
我们需要维护的操作是维护 $n$ 个关于 $F,G$ 的点值数组。
- 对于新点 $u$ ,$F$ 的前缀赋值为 $x$ ,后缀赋值为 $1$ 。$G$ 数组赋值为 $0$ 。
- 对于 $(u,v)$ ,我们现将 $v$ 的 $F$数组全体加一,然后将两个 $F$ 数组对应位置相乘,将 $G$ 数组对应位置相加
- 将 $u$ 的 $F$ 数组加到 $G$ 数组上。
注意到这变换是相同的,不妨设计一个变换形式来实现快速转移。
定义变换 $(a,b,c,d)$ 的作用为
$$
(a,b,c,d):(f,g)\longrightarrow (af+b,cf+g+d)
$$
容易将上方三个式子写成相对应的变换,但我们要对于变换实现乘法
$$
(a_1,b_1,c_1,d_1)\cdot (a_2,b_2,c_2,d_2)
$$
这个也很好推
$$
(a_1,b_1,c_1,d_1):(f,g)\longrightarrow (a_1f+b_1,c_1f+g+d_1)\\(a_2,b_2,c_2,d_2):(a_1f+b1,c_1f+g+d_1)\longrightarrow (a_1a_2f+b_1a_2+b_2,(c_2a_1+c_1)f+g+c_2b_1+d_1+d_2)
$$
那么
$$
(a_1,b_1,c_1,d_1)\cdot(a_2,b_2,c_2,d_2)=(a_1a_2,b_1a_2+b_2,c_2a_1+c_1,c_2b_1+d_1+d_2)
$$
这样我们就可以知道每个点所对应的变换来快速求出答案了。
但这还是 $\mathcal O(nkw)$ 的。(悲
注意到上述操作很像区间加法,不妨用线段树支持变换。
具体来讲,我们类似打区间 $tag$ ,标记下传的方式可以得到每个点的变换,而对于合并子树也类似线段树合并。
而这个线段树合并需要支持标记下传,并且由于变换的乘法没有交换律我们需要考虑一下非空的子结点是 $u/v$ 。
这个线段树合并的时/空复杂度也是 $\mathcal O(n\log n)$ 的,因为标记下传仅在两个线段树的 $\cap$ 下传,时间复杂度依然是 $\mathcal O(n\log n)$ 的,所以空间复杂度仅多了常数 $(2)$ 倍。
由于我们需要求 $x$ 在 $1\sim n+1$ 的点值需要将上述做法重复 $n+1$ 遍。
即总时间复杂度为 $\mathcal O(n^2\log n)$ ,但这常数肉眼可见的大,所以被暴力碾了。
https://loj.ac/s/1084408