题解 LGP4365 【[九省联考2018]秘密袭击coat】
前置知识
线段树合并,拉格朗日插值
大概后文重点分析了线段树合并的复杂度
\(\texttt{Solution}\)
一脸 dp 的样子,我们来推一推式子
枚举 \(S\) 为一个点数不小于 \(k\) 的树上连通块
记 \(val(S,k)\) 为集合 \(S\) 中的第 \(k\) 大权值
\(cnt(S,v)\) 为集合 \(S\) 中不小于 \(v\) 的元素个数
此时我们可以丢掉 \(S\) 中点数的限制,交换求和符号
即我们需要对于每个 \(v\) 求出有多少个树上连通块里权值不小于 \(v\) 的点个数不小于 \(k\)
设计一个暴力的 dp 状态:
\(f_{x,i,j}\) 表示以点 \(x\) 为根的连通块中权值不小于 \(i\) 的点有 \(j\) 个的连通块数
转移显然是树上背包
最后的答案应该是 \(\sum_{i}\sum_{x}\sum_{j=k}^nf_{x,i,j}\)
暴力的复杂度很高,我们考虑优化
广为人知的是,树上背包问题是一个卷积,我们用生成函数的角度思考
记 \(F_{x,i}(z)=\sum_{j=0}^nf_{x,i,j}x^j\)
那么 \(F_{x,i}=z^{[d_x\geq i]}\prod_{y}(F_{y,i}+1)\)
由于我们最后要求 \(\sum_i\sum_x\sum_{j=k}^n[z^j]F_{x,i}\)
我们设 \(G_{x,i}=\sum_{y\in sub(x)}F_{x,i}\)
转移显然是 \(G_{x,i}=F_{x,i}+\sum_{y\in son(x)}G{y,i}\)
答案简化为 \(\sum_i\sum_{j=k}^n[z^j]G_{1,i}\)
由于转移中与 \(i\) 的关联极小,我们希望对于所有 \(i\in[1,w]\) 做整体 dp
由于多项式乘法复杂度较高,我们考虑带入点值计算多项式,最后再插值回来
我们现在只需对于点值 \([0,n]\) 都算一遍整体 dp 即可
考虑建立以 \(i\) 为下标的线段树,所有的转移都能用矩阵表示,即:
\([f,g,1]\times \left[\begin{matrix}a&c&0\\0&1&0\\b&d& 1\end{matrix}\right]\)
考虑矩阵能简化为四元组运算的形式,即大多数题解中提到的“变换”
容易讨论,不展开叙述
本题的线段树合并与一般线段树合并不同的地方在于其区间的修改
例如线段树的初值:
\(F_{x,i}=z^{[i\leq d_x]}\),其中 \(z\) 是枚举的点值,为常数
我们应该将 \([1,d_x]\) 赋值为 \(z\),\([d_x+1,w]\) 赋值为 \(1\)
为了让复杂度正确,我们显然不能让点数达到 \(O(nw)\)
我们直接利用懒标记,显然初始节点个数确为 \(O(n\log w)\)
对于线段树合并操作,我们知道我们得保证遍历一个点后“删除”一个点复杂度才正确
我们考虑合并时直接在存在一棵线段树节点没有儿子时返回即可
由于有一棵树往下已经没有儿子,那么实际上这段区间的矩阵懒标记均相同,容易处理
对于 merge 里 pushdown ,一定是两个线段树节点此时均有儿子时才会去做,事实上此时两节点一定会有左右儿子,所以并不增加节点个数
总复杂度为 \(O(n^2\log w)\)
众所周知区间修改的 \(\log\) 常数不小,线段树里还有矩阵乘法,属于是跑不过暴力(