「LibreOJ NOI Round #2」黄金矿工
超级大毒瘤题
数据结构维护动态模拟费用流?
费用流模型显然就略了
这里由于是父亲到儿子的有向边所以就特殊考虑
把金子的权值加上根节点到该节点的距离
把矿工的权值减去根节点到该节点的距离
那么就不需要边权了只需要考虑金子和矿工的相互关系
注意到这就变成了二分图最大权匹配
效仿费用流的反向边
我们可以考虑选了一个权值为A的金子以后在那里加上一个权值为-A的矿工表示反悔
那么我们一个金子B选了这个多出来的矿工就表示我原来与A金子配对的矿工放弃了原来的那个A金子选择当前的B金子
对称地,我们选了权值为A的矿工以后就在那里加上一个权值为-A的金子表示反悔
现在我们考虑加入一个矿工/金子以后的增广
先考虑加入矿工这个相对比较简单
显然加入的这个点的子树中的所有金子都是可以和它匹配的
但是只有这些吗?
我们考虑修改一些操作
如果这个点(设为A)的祖先上有一个点B的矿工与这个点的子树内的一个金子C配对了
那么对于点B子树内的一个没有配对的金子D而言
我们可以调整一下让A和C配对,B和D配对
这样在当前的操作事实上等价于获得了A和D配对的收益
所以事实上我们考虑点A深度最浅的祖先B的矿工满足到其点A子树内的某点的金子有匹配
我们能选的金子事实上是B的子树内的所有金子
在树链剖分以后
找B点可以树上用一颗线段树实现添加和查找
查询子树最大值可以用一棵单点查询区间取max的线段树维护
我们再考虑加入金子
这个就相对复杂一点
假设我们在A点加入金子
因为我们发现任意一个点B上的矿工只要满足其的子树内某个金子D与A的某个祖先C上的矿工有匹配关系
那么只需要调整成C和A配,B和D就可以等价于A和B配对
于是这里在跳树链的时候需要维护每个点轻儿子的矿工最大权值
那么这样就相当于每次查询重链的一部分的子树最大值
维护轻儿子具体而言就是在修改某点的匹配或权值后
跳树链对每条经过链顶的父亲更新答案即可
代码5.6k很好写