首页 > 其他分享 >[CSP-S2019] 树的重心 题解

[CSP-S2019] 树的重心 题解

时间:2023-10-15 22:13:16浏览次数:34  
标签:子树 log 重心 题解 le siz S2019 CSP 子树内

[CSP-S2019] 树的重心

因为这道题令我十分兴奋,所以来写一下做完后的思考。

这道题用到了树的重心的种种性质,在写解法的时候会一一点出其用处。

首先,枚举每一条边,然后各自 \(O(n)\) 扫一次的 \(O(n^2)\) 做法是简单的。

那么接下来,就会出现不同的解法了:

  • 优化 \(O(n)\) 求解的过程至 \(O(\log n)\)

  • 利用 \(O(n)\) 状态 \(O(n)\) 求解的套路:枚举每一个的贡献。

那么接下来分开讲述两种做法


倍增优化求重心的过程

  • 如果 \(x\) 不为重心,那么重心要么在其重儿子内,要么在其子树外。

那么找一颗子树内的重心,就可以倍增求解了。

也就是删掉一个边 \((x, y)\) 之后(假定 \(y\) 是 \(x\) 的父亲)\(x\) 子树内的重心是简单的,但是子树外(也就是 \(y\) 所在的子树)的重心不太好求解。

类似换根 DP 的思路,发现 \(y\) 所在子树的倍增数组,只会影响到 \(y\) 到根路径上的每一个点。

于是每一次 DFS 下去,\(O(\log n)\) 的更新倍增数组,然后 \(O(\log n + \log n)\) 的求两边的重心即可。


枚举每一个点的贡献

此时我们需要考虑的是一个点 \(x\) 如何变成重心。

  • 删除 \(x\) 子树中的某棵子树

  • 删除 \(x\) 子树外的某棵子树

  • 保留某一棵包含 \(x\) 子树

如果可以稍微合并一下,那么第二点和第三点是可以放在一起的。

但是如此分类讨论是相当难做的,考虑如何减少某一种状态。

  • 把两棵树通过一条边相连得到一棵新的树,则新的重心在较大的一棵树一侧的连接点原重心之间的简单路径上。如果两棵树大小一样,则重心就是两个连接点。

同理的,删除一棵子树,那么重心会向相离的方向移动。

那么删除 \(x\) 子树内的某棵子树,\(x\) 能够成为重心必须满足重心在 \(x\) 的子树内。

那么如果我们以某一个重心为根,意味着除了根,那么就没有满足上述条件的点了,此时我们只需要讨论子树外的情况即可。

  • 某个点是树的重心等价于它最大子树大小不大于整棵树大小的一半

假设我们删除了大小为 \(s\) 的连通块,那么 \(x\) 可以成为重心则需要满足:

\[\begin{cases} n - s - siz_x \le \left \lfloor \frac {n - s}{2} \right \rfloor \\ mx_x \le \left \lfloor \frac {n - s}{2} \right \rfloor \end{cases} \]

其中 \(siz_x\) 表示 \(x\) 所在子树的大小,\(mx_x\) 表示 \(x\) 子树的最大大小,也就是 \(mx_x = \max siz_y\)。

稍微整理一下,就可以得到:

\[n - 2 siz_x \le s \le n - 2 mx_x \]

那么考虑 \(x\) 子树外有那些满足此条件的子树即可。

但是发现 \(x\) 的祖先 \(f\) 的大小并不可以是 \(siz_f\),而是 \(n - siz_f\),这是在 DFS 的过程中好维护的。

最终利用树状数组维护一下即可。

但是重心本身的答案并不能如此维护,我们需要单独做一次。

设 \(X\) 为重心 \(G\) 作为根的最大的子树,\(Y\) 为次大子树,那么对于某个点 \(x\) 需要分类讨论一下:

\[\begin{cases} \max (siz_X - s, siz_Y) \le \left \lfloor \frac {n - s}{2} \right \rfloor &\text{x 在 X 子树内} \\ siz_X \le \left \lfloor \frac {n - s}{2} \right \rfloor &\text{x 不在 X 子树内} \end{cases} \]

这是容易 \(O(n)\) 做一次的。

于是此算法的复杂度为 \(O(n \log n)\),代码应该不是很难。

可以参考代码内的注释:https://loj.ac/s/1911177

然而本算法仍然可以有优化的空间,可以参考 [CSP-S2019]树的重心 题解 - TEoS - 博客园,做到 \(O(n)\) 求解。


小小总结

本题可以说是非常开放的题,因为存在很多解法,这里并没有涵盖完。

足以说明在 CSP 考试中,不能局限于某一个算法,更多的尝试可能带来更多的解法。

而在本题中体现出了解决问题的常用思想:

  • 优化暴力 \(O(1) - O(n)\) 平衡为 \(O(n \log n) - O(\log n)\),也就是算法 1。

  • 多状态 \(O(n)\) 暴力求和转化为每一个元素的贡献。

  • 利用信息所附带的信息(性质)推导方向,优化代码。

倍增!非常优秀的一个做法,是考点的长青树。这需要重重注意,细细揣摩。

标签:子树,log,重心,题解,le,siz,S2019,CSP,子树内
From: https://www.cnblogs.com/jeefy/p/17763214.html

相关文章

  • P9290 Luna likes Love 题解
    原题:[洛谷P9310]([P9310EGOI2021]LunalikesLove/卢娜爱磕cp-洛谷|计算机科学教育新生态(luogu.com.cn))题目大意给定一个长度为\(\large2n(n\leq10^5)\)的序列,序列中\(\large1\simn\)的每一个数都恰好出现两次。可进行两种操作:交换两个相邻的数的位置。......
  • 2023 香山杯 RE部分题解
      URL从哪里来 main函数断点下载这里 然后可以看到TempFileName,是out.exe.tmp,还包含路径,直接提取出来用IDA打开,一开始被url误导了,看到了下面的RC4加密去了,使用findcryt软件,看到一个base64加密,交叉引用 在这动态调试这个函数 里面的a1,有一串字符是base64密文 ,解......
  • 【ZROJ2730】简单题 可持久化分块题解
    Description给定一棵\(n\)个节点的树,每次询问编号为\([l,r]\)的点中有多少个是祖先关系。\(n,q\le10^5\)。Solution直接做的话树上的祖先关系不好统计,那么转化到\(\texttt{dfs}\)序上,如果\(u\)是\(v\)的祖先那么\(dfn_u\ledfn_v<dfn_u+siz_u\)。把\([d......
  • CSP 2023 游记
    笔者今年(2023年)高一,坐标SC。2023.9.16初赛,然而运势是大凶。真的就我是大凶两点过到了教科院附中门口,没看到教练,同校OIer也都已经进去了。进校之后遇到了这正找考场的sh。14:30开始考试,考生(包括本人)有且仅有4个人。。。发现有一道选择题就是P2765,甚至是样例,所以直接......
  • AtCoder Beginner Contest 324 DF题题解
    比赛链接D-SquarePermutation其实比较简单,但是比赛时候脑子不转了,竟然在尝试枚举全排列,然后算了一下复杂度直接不会做了。正解应该是枚举完全平方数,底数枚举到\(sqrt(10^{14})\)即可,因为n最大为13。然后统计一下这个完全平方数各个数字出现了多少个,和读入的比较一下是......
  • 网络规划设计师真题解析--HDLC(帧类型)
    HDLC协议通信过程如下图所示,其中属于U帧的是(13)。(2021)A.仅SABME          B.SABME和UA C.SABME、UA和REJ,1    D.SABME、UA和I,0,0答案:B解析:HDLC帧类型如图:bit01234567I帧0N(S)发送帧序号3bit,取值23(0-7)P/FN(R)下一个预期要接收帧的序号3bit,取值23(0-7)S帧10S......
  • ABC324题解
    A/B赛时没打。C暴力判断是相等s[i]==t还是替换了一个字符,或者是添加/删除了一个字符。最后两个判断只需要交换一下\(s\)和\(t\)的顺序就可以共用一个函数了。D注意到\(N\le13\),所以平方数不会超过\(v=10^{13}\),很容易想到暴力枚举\(\sqrtv\)以内的数,判断是否......
  • P9517 drink 题解
    P9517drink题解Part1提示题目传送门欢迎大家指出错误并私信这个蒟蒻欢迎大家在下方评论区写出自己的疑问(记得@这个蒟蒻)Part2更新日志2023-08-1218:06文章完成2023-08-1415:53文章通过审核Part3解析这道题考场上用的查找做的。先用一个结构体分别表示......
  • csp2023 第一轮游记
    csp2023第一轮游记Day-20AFO.Day0考试是周六,所以还是正常在学校上课,除了有点担心,还是有点担心(主要是没复习)。考前打了一个代码:#include<bits/stdc++.h>usingnamespacestd;intrp;intmain(){ for(inti=1;;i++) { rp++; printf("%d\n",rp); } re......
  • P9686 Judg. 题解
    P9686Judg.题解Part1提示题目传送门欢迎大家指出错误并私信这个蒟蒻欢迎大家在下方评论区写出自己的疑问(记得@这个蒟蒻)Part2更新日志2023-10-0215:50文章完成2023-10-0412:37文章通过审核Part3解析一道简单模拟。这道题最简单的方法就是直接在for循......