zoukankan      html  css  js  c++  java
  • [常见做法整合]CSP-S2019 D2T3 树的重心

    CSP-S2019 D2T3 树的重心(centroid)

    本题解是题解栏内一些常见思路的集合。

    为了篇幅紧凑,在一些地方我可能跳过了证明/阐述的不是怎么详细,如果希望看到某一个思路的详细阐述/代码,可以点击相关的超链接。

    思路

    本题的部分分启发我们去找性质:

    1. 链的部分分启发我们去考虑树链剖分
    2. 二叉树的部分分启发我们去考虑以重心为根的情况。
    3. 由于要同时考虑子树与外子树的情况,这启发我们想到换根法

    性质:

    1. 重心(u)在根节点所在的重链上。
    2. (uin son_{rt})(v)(u)的重心,则(rt)的重心为(v)的祖先。
    3. (u)为重心,只有(u)的重儿子(或父亲)有可能是重心。

    计数方法:

    1. 对于每一个点,我们计算它作为重心的次数:这会导致实现偏向数据结构(BIT、可持久化线段树、树状数组等)。
    2. 对于每一个分割,我们去找两课树的重心:这回导致实现偏向图论类方法(树链剖分、找重儿子、倍增等)。

    方法0:考虑点,只考虑定义

    代码 类似思路的题解

    考虑一个点(u),我们想要知道,它会成为几次重心。

    将树在(u)处定根,设其最大的子树大小为(S=siz_w),则可以分为两种情况:

    1. 删去的边不在(tree_w)中,(tree_v otsubseteq tree_w):则(siz_vle n-2S)时,(u)成为重心。
    2. 删去的边在(tree_w)中:设除了(tree_w)最大的子树大小为(T),则(2S-nle siz_vle n-2T)(u)成为重心。

    因此,我们考虑处理出以(u)为根,各个儿子的({siz})的可重集合的情况,再查询一段区间内的(siz)的个数即可。

    维护方法

    可以用可持久化线段树(可能可以线段树合并/将所有查询离线化)维护。

    特别地,(fa_u)的情况,相当于(tree-anc_u-tree_u)({u}+anc_u-{rt})取反。(其中,(anc_u)表示(u)的所有祖先节点)

    方法1:考虑点,以重心为根

    我们先找到重心(rt),并以它作为根。这样和随意选根有什么区别呢?

    性质:若(x e rt)为重心,则删去的边((u,v))一定不在(tree_x)内。

    因此,对一个点(u e rt),他作为重心仅当删去了一条边((x,y)),且:((x,y))不在(tree_u)内,(n-2s_xle Sle n-2g_x)。(设树减少的大小为(S)

    对于根的情况,可以另外(分成割去的边在重儿子子树内与不在重儿子子树内)判断。

    可以用树状数组维护,具体见这篇题解

    方法2:考虑边

    考虑一种删边情况,我们需要快速求出,划分后的所有重心。

    考虑如何求一棵树的重心:因为重心一定在根节点所在重链上,从根一直跳重儿子,直到找到最深的(v)使得,(2s_v > s_u),则(v)(可能还有它的重儿子)为重心。此过程可以用倍增加速。

    由这种做法,我们可以在树链剖分,并预处理倍增数组之后(O(log n))地求出任何子树的重心。

    高赞题解的变体

    我们考虑一个划分((u,v)),不妨设(dep_u>dep_v)

    考虑如何求(tree_u)的重心:我们从(u)出发,一直向重儿子跳,跳到找到重心(即,重儿子的子树大小不超过原树的一半)为止。

    考虑如何求出(tree-tree_u)的重心:我们先将根换到(v)处(此时只改变了两个节点的关系),这样实际上就相当于求(tree_u)的重心!

    具体实现在

    方法3:考虑边,某神奇的(O(n))做法

    就如之前所说的,可以在(O(n))计算出所有子树的重心,但是很难对去掉子树的部分找到一个重心单调移动的计算序列……

    以重心为根,考虑删去的边在哪棵子树内:

    1. 不在重儿子的子树内:则枚举所有可能的子树大小,在根所在的重链上面走就好了。
    2. 在重儿子的子树内:
      1. 重儿子仍然为重儿子:此时,根仍然为重心。
      2. 次重儿子变为了重儿子:在次重儿子的重链上走即可。

    这样就用纯图论方法完成了这题。

    参考资料

  • 相关阅读:
    日期时间工具(dayjs)的使用
    Apache JMeter下载使用
    webpack 干货总结
    常见设计模式——模板方法
    常见设计模式——代理模式
    Codeforces Round #340 (Div. 2)E
    HDU 4547
    HDU 2586
    LCA算法的介绍与模板
    1073. 负二进制数相加
  • 原文地址:https://www.cnblogs.com/topsecret/p/12606466.html
Copyright © 2011-2022 走看看