「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很好写

code

posted @ 2020-06-29 22:00  deaf  阅读(405)  评论(0编辑  收藏  举报