zoukankan      html  css  js  c++  java
  • [AGC023F]01 on Tree 另解

    题目链接

    题意

    给定 $n$ 个点的有根树,每个顶点有权值 $1$ 或 $0$. 请确定一个拓扑序,即父结点先于子结点出现,使得该拓扑序的权值序列逆序数最小。

    $n le 2 imes10^5$.

    题解

    假设两棵子树的方案已知,要合并它们。

    前导 $0$ 肯定抽到前头来,后缀 $1$ 肯定排到最后去。考虑两子树的形如 $11cdots100cdots0$ 的段孰先孰后,反正混在一起肯定不优。

    假设第一棵子树的这样的段是 $A_1 imes1+A_0 imes0$, 第二棵子树的这样的段是 $B_1 imes1+B_0 imes0$, 则第一段放在前面产生逆序数 $A_1B_0$, 否则产生逆序数 $A_0B_1$.

    所以第一棵子树的这个段在前等价于 $A_1B_0 le A_0B_1$, 也就是 ${A_1 over A_0} le {B_1 over B_0}$.

    我们把形如 $11cdots100cdots0$ 的段叫做 $oldsymbol{01}$ 段,其 $1$, $0$ 的个数比叫做该 $01$ 段的密度

    前导 $0$ 也就是 $0 imes1+n imes0$, 同理后缀 $1$ 就是 $n imes1+0 imes0$, 可以统一处理。因此密度的取值从 $0$ 到 $+infty$ 不等。

    如果同一棵子树里,出现了两个相邻的 $01$ 段,前者密度大于后者,那么我们根据上述引理推断,不可能有另一个段插在它们中间,因此它们被合并成一个段。

    这样的段,由于不可再分,在表现上,和把这其中所有的 $1$ 放在前头、所有的 $0$ 放在后头得到的 $01$ 段并无不同。

    因此,我们就得到了算法:

    按任意逆拓扑序遍历树,维护当前的答案中的每个 $01$ 段。遍历一个点时,先把所有子点的段按有序数组合并起来,然后在前头插入一个由其权值组成的短 $01$ 段,不断合并(顺便记录其中逆序数)直到该段密度严格递增。

    最后把所有段取出来,再计算一次逆序数。

    这里需要维护有序数组的归并、取出/删除/插入有序数组的最小元,这些都可以用斜堆办到。

    代码链接

    标解思路类似,但是用的是堆和并查集来维护合并操作。我的这做法貌似快些,截至提交时为 AtCoder 速度第一名。

  • 相关阅读:
    VirtualBox 安装增强工具Guest Additions 【转载】
    全面认识计算机启动过程【转载】
    Linux下使用mke2fsk格式化虚拟磁盘分区的方法
    什么是posix
    bochs默认没有pci的
    剑指offer中二进制中1的个数
    原码、补码、反码的概念
    初识hadoop
    chord原理的解读
    深度学习概述:从感知机到深度网络
  • 原文地址:https://www.cnblogs.com/nealchen/p/AGC023F.html
Copyright © 2011-2022 走看看