zoukankan      html  css  js  c++  java
  • 有根树

    显然我们会选择(w)最大的点加入答案。
    当被插入的(w)值越小,插入的节点数会越大。
    被插入的(w)值随着插入的节点数变得越来越小。
    所以我们其实是要求两个单调函数的交点。
    可以把(w)从大到小排序后把最大的值插入到解中。
    由于(w)的权值只有(n)种,所以可以桶排序。
    考虑加速这个过程。
    一个想法是二分,但是是不可行的。
    如果要二分,则我们需要求第k大,除了分块别无它法。
    注意在二分做法中到我们并没有利用以前的解的信息,所以可以进行调整。
    假设现在我们选择的点数是(X),没被选的点(w)最大是(Y),被选的点的最小(w)(z)
    根据条件,一定满足(Y<z)
    如果我们正确的维护的(w)值,调整的过程就是把(z)从C中删除,或者把(Y)插入C。
    这样子必定会是X减少/Y增加。
    如果插入一个点,最多会有一个点的(w)(>Y)。如果有多个,则这些点肯定是父亲/儿子关系,一个的值肯定比另一个大。
    这可能会导致(Y>z)
    我们要正确的维护(w),当(Y>z),要把(Y)(z)交换。
    交换后调整即可。
    由于最多有一个点使得权值(=Y+1),所以我们最多把1个节点从非C集合放在C集合中。
    删除同理。
    注意到我们维护的是不在C中的最大值,在C中的最小值。
    问题等同于链+,全局最大值,使用轻重链剖分+线段树维护。
    我们得到了一个时间复杂度(O(nlog_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(nlog_2n))的时间解决了这个问题。
    总结:这道题的核心想法是转化模型,优化调整的过程。
    标准算法充分的利用了此题的性质。
    这是我认为在NOI WC2020 最好的一道题。

  • 相关阅读:
    WARNING OGG-00706 Failed to add supplemental log group on table
    Lucene&Solr框架之第一篇
    SSM框架整合之练习篇
    SpringMVC框架之第四篇
    SpringMVC框架之第三篇
    SpringMVC框架之第二篇
    SpringMVC框架之第一篇
    MyBatis框架之第三篇
    MyBatis框架之第二篇
    maven仓库之第二篇
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/13671259.html
Copyright © 2011-2022 走看看