Processing math: 0%

有根树

显然我们会选择w最大的点加入答案。
当被插入的w值越小,插入的节点数会越大。
被插入的w值随着插入的节点数变得越来越小。
所以我们其实是要求两个单调函数的交点。
可以把w从大到小排序后把最大的值插入到解中。
由于w的权值只有n种,所以可以桶排序。
考虑加速这个过程。
一个想法是二分,但是是不可行的。
如果要二分,则我们需要求第k大,除了分块别无它法。
注意在二分做法中到我们并没有利用以前的解的信息,所以可以进行调整。
假设现在我们选择的点数是X,没被选的点w最大是Y,被选的点的最小wz
根据条件,一定满足Y<z
如果我们正确的维护的w值,调整的过程就是把z从C中删除,或者把Y插入C。
这样子必定会是X减少/Y增加。
如果插入一个点,最多会有一个点的w>Y。如果有多个,则这些点肯定是父亲/儿子关系,一个的值肯定比另一个大。
这可能会导致Y>z
我们要正确的维护w,当Y>z,要把Yz交换。
交换后调整即可。
由于最多有一个点使得权值=Y+1,所以我们最多把1个节点从非C集合放在C集合中。
删除同理。
注意到我们维护的是不在C中的最大值,在C中的最小值。
问题等同于链+,全局最大值,使用轻重链剖分+线段树维护。
我们得到了一个时间复杂度O(n\log_2^2n),空间复杂度O(n)的算法。
这样子时间复杂度比正解高,但是如果常数较小可以通过。
当我们调整的时候,其实我们在做这么一个过程:
X<Y,如果有节点的权值=X,且该节点不在C中,则X+=1,否则Y-=1
X>Y,如果有节点的权值=Y,且该节点在C中,则X-=1,否则Y+=1
可以看做暴力的寻找最大/小值。
根据之前的分析,最多会跳1次。
还是考虑对树进行轻重链剖分。对于每条重链,根据之前的分析,我们维护最大/最小值。
会发现,对于一条重链,只有最顶端/底端的节点会成为最大/小值。
所以可以对每条重链使用一个set维护最小/大值。
除此之外,我们还需维护最大/小值中,是否有权值为X的点。
在我们插入/删除一个点后,我们可能需要对它能够跳到的重链上的点的权值+1/-1,而这个过程有nlogn次。
可以使用链表。在不在C/在C元素的桶中,开n个链表,第x个链表维护权值x的点。
在对节点+1/-1时,从对应的链表中删除原来值的节点,插入新的值的节点。
借助dfs序,我们可以在O(1)的时间复杂度内求出一个点的权值是否要被修改,这样子可以O(1)维护权值。
在插入/删除点的时候,由于我们通过以前的信息不能知道这个点的权值,使用dfs序+树状数组求出它的权值。同时更新当前链上的最大/小值。
这个操作在一个插入/删除操作内最多出现1次,时间复杂度为\log_2n
综上,我们使用O(n)的空间,O(n\log_2n)的时间解决了这个问题。
总结:这道题的核心想法是转化模型,优化调整的过程。
标准算法充分的利用了此题的性质。
这是我认为在NOI WC2020 最好的一道题。

posted @   celerity1  阅读(171)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示