• prufer序列学习笔记


    prufer序列简介

    将一棵无根树和一个值域在 ([1,n]) 之间的长为 (n-2) 的序列 一一对应

    构造

    每次选择一个标号最小的叶子结点删除掉,将删除的节点的父亲记录在 prufer 序列的末尾。重复此过程。

    使用堆维护的话复杂度是 (O(nlog n)) 的。

    线性构造

    维护一个单调递增的指针 (p),初始时 (p) 指向编号最小的叶结点。每次我们删除一个节点的时候,如果其父亲变成叶子,记其父亲为(x)。若(x<p),则下一步直接删除(x),继续进行。否则的话让指针 (p) 自增直到遇到一个未被删除叶结点为止。证明也很简单,在(p)之前的度数为(1)的点要么已经被(p)自增的时候扫过去了,要么是扫过去了以后变成叶子,会被贪心的先选择。

    时间复杂度(O(n))

    还原

    整体过程大概就是构造的逆变换。有一个关键性质是,设(d_i)(i)的度数,那么(i)在prufer序列中的出现次数为(d_i-1)。我们可以根据prufer序列确定每一个顶点的度数。

    朴素做法还是用堆维护编号最小的叶子节点,从前往后依次扫描prufer序列,当前prufer序列中的元素就是编号最小的叶子的父亲。时间复杂度 (O(nlog n))

    线性还原

    类似线性构造,我们将用堆维护编号最小的叶子换成单调递增的指针+贪心判断即可。时间复杂度(O(n))

    应用

    Cayley 公式

    用于prufer序列与无根树的一一对应关系,我们可以得到

    (n)个点的完全图的有标号生成树个数为

    [n^{n-2} ]

    也可以表述为:(n)个点的本质不同有标号无根树的个数为(n^{n-2})

    有标号有根树

    直接在无根树中选择一个点作为根即可。或者可以理解为在构造prufer序列的时候剩下两个点,再选一个点作为叶子,另一个作为根。

    方案数就是

    [n^{n-1} ]

    有标号有根树森林

    树的个数确定

    假设数的个数为(m)

    建一个虚点,连这(m)个节点,因为一个点的度数是 prufer 序列中的出现次数(+1),所以这个虚点要在 prufer 序列中出现 (m-1) 次,再加上是 (n+1) 个节点的有根树,也就是

    [inom{n-1}{m-1}n^{n-m}=inom{n}{m}mn^{n-m-1} ]

    数的个数不确定

    如果我们不需要确定根的个数,即对所有(m)求和得到

    [sum_{m=1}inom{n-1}{m-1}n^{n-m}=sum_{m=0}inom{n-1}{m}n^{n-1-m}=(n+1)^{n-1} ]

    限制度数的无根树

    设度数为(d_i),方案数是

    [inom{n-2}{d_i-1}(n-1)^{n-d_i-1} ]

    多个点的度数限制可以由此推广

    特别的,如果所有点的度数都有限制

    [inom{n-2}{d_1-1,d_2-1,d_3-1,cdots,d_n-1}=frac{(n-2)!}{prod(d_i-1)!} ]

    连通块建树

    证明详见 OI wiki

    (k) 个连通块,每个连通块大小为 (a_i),求将这些连通块连成树的方案数。

    (sum a_i=n),答案为

    [n^{k-2}prod a_i ]

  • 相关阅读:
    sql优化
    一些有用的单词(1)
    用到的 Sed 注解
    终端工具注册码
    nginx四层、七层负载均衡配置示例
    http 状态码
    04. Golang 数据类型
    03. Golang 特性
    02. Go 命令
    01. GOPATH 目录结构划分的两种风格
  • 原文地址:https://www.cnblogs.com/harryzhr/p/14960543.html
Copyright © 2020-2023  润新知