CF526G - Spiders Evil Plan 题解

OmNom……引起了回忆………………

我想说,这题真是太神仙了 %%%%%%%%%%%%%%


首先显然选的每条路径都是以叶子为两端的,而且不在不得已的情况下不会选重复的叶子。那么容易发现,对 \(2x\) 个叶子,选择它们选出的路径的并,最优也优不过它们生成的虚树。实际上稍微动动脑子就能证明:对任意 \(2x\) 个叶子,一定存在将它们两两配对选出 \(x\) 条路径的方式,使得这些路径的并为它们生成的虚树。

稍微动脑子就能会的(感性)证明:考虑归纳,那么只要证对任意 \(2x\) 个叶子,一定能找到一对叶子,它们的路径和剩下来 \(2x-2\) 个叶子生成的虚树的并等于这 \(2x\) 个叶子生成的虚树。根据虚树的每个非叶节点至少有两个儿子这个性质,这只要分个几类就随便证了,再此不赘述。

那么询问就转化成了:选出任意 \(2y\) 个叶子生成的包含 \(x\) 的虚树,求其中边权和最大的方案。不难想到以 \(x\) 为根来搞,这样由于虚树必须包含 \(x\),那么这棵虚树显然是所有叶子到根(\(x\))的路径的并。先不管它们生成的虚树能不能包含 \(x\),那这不就是攻略那题了吗?长剖随便做。然后如果要符合要求的话,必须满足 \(x\) 是叶子并且被选或者 \(x\) 的两个不同儿子子树里都有被选的叶子。这是不一定满足的,但是可以发现只需要进行一次调整即可满足,调整指的是删去一个叶子并加入一个叶子。删去就删当前选的贡献最小的,加入就加贡献最大的。当然具体是什么不用说了,因为这个方法本来就是暴力,过不去。

瓶颈在于我们每次都搞了个不同的根,而这只可能在离线的时候有效,可以存下来然后换根。我们发现,上述方法中第一个选的那个贡献最大的是一定不会被删的,因为 \(2y\) 是偶数,要删的话最靠前也是第 \(2\) 名。而这个贡献最大的显然是根所在长链包含的叶子,也就是到根距离最大的叶子。根据直径的性质,这一定是直径的一个端点!也就是说任选一条直径,每组询问选的最优叶子集合一定包含至少一个端点(有多条直径不用怕,是等效的)。

于是考虑以两个直径端点分别为根,每次询问在两个方案里分别查询取 \(\max\)。考虑如何查询。我们考虑先选出最优的 \(2y-1\)(有一个叶子是直径端点(根),已经被选)个叶子,然后再调整使得 \(x\) 被包含进去。不难发现,这样设根,每组选的叶子的答案也一定是它们到根的路径的并,因为根必须被选。那依然可以长剖,并且只需要进行两次长剖,不像上面那种暴力,竟然想在换根的时候搞不可遗传的长剖。

那考虑如何调整。如果 \(x\) 已经被选了(一个节点是否被选,可以预处理出所有长链的排名,然后看所在长链是否排名靠前来常数时间查询),那没事了。否则,将 \(x\) 加进去(贡献显然是它到往上第一个被选的祖先的距离,可以倍增找到(在无边权时跳长链是根号的,但是这题有边权,不行了))之后,只需要删掉原来的任意一个叶子即可。考虑删掉每个叶子的贡献(当然是负的),那就是到往上第一个子树包含其它被选叶子的祖先的距离啊……那么贡献最大的显然是按贪心最后一个选的,直接调用前缀和就好了;但有一个特殊情况:当 \(x\) 加入之后,它到往上第一个被选的祖先子树内如果只有一个被选叶子的话,那么按照之前说的,应该还要往上消,但是 \(x\) 的加入能给它保护到「它到往上第一个被选的祖先」,这个特判一下就好。

总复杂度是线对,因为有倍增。

code

posted @ 2021-02-04 16:40  ycx060617  阅读(82)  评论(0编辑  收藏  举报