树分治

点分治

思想

回想序列分治的做法:递归统计两个区间,在统计跨两个区间的贡献

对应到树上也类似:找一个分割点,统计子树的贡献,再统计跨子树的贡献

由于路径都可以被某一级重心统计到,所以点分治长于做路径统计问题

找树的中心

树的中心:以它为根时的最大子树最小的点

处理方式:开全局变量\(maxsiz\),dfs找出每棵子树的大小(父亲的子树大小用\(sum-\sum siz[v]\)计算)

目的:使每次分割的子树尽量小

流程

1、找到树的中心;

2、统计子树中和该点有关的量;

3、删除该点,分裂出若干棵树,对每棵树做一遍点分治;

为什么时间复杂度是\(O(n\log n)\)

对每棵树处理次数为\(n,siz_1,siz_2,...,siz_k\)

总和为\(n+\frac{n}{p_1}+\frac{n}{p_2}+...+\frac{n}{p_k}\)

大约和调和级数同阶,所以为\(O(n\log n)\)

P6626 [省选联考 2020 B 卷] 消息传递

点分治模板题

开桶,对子树内点,用桶统计子树外(过树的中心)贡献,对中心,直接统计子树贡献

进子树前记得去掉该子树的贡献

由于每个点都会成为中心,可以统计完全

P5984 [PA2019]Podatki drogowe

拼凑型题目,对于熟悉的人来说没有难处

1、路径第\(k\)大:二分答案+点分治计数

2、大数比较:主席树+哈希

3、发现值域过大,考虑在路径集内二分

4、发现路径集找权值中位数比较困难,考虑随机找一条权值在\(l,r\)之内的路径来做(随机二分)

5、

点分树

带修改的点分治,支持在线

点分治过程中,上一级重心向下一级连边,形成一棵有根树

性质:

1、树高\(O(\log n)\),一些看似暴力的东西也可以直接存(如每个点存储该子树全部信息,这是\(O(n\log n)\)的)

2、在点分上,\(LCA(x,y)\)一定在原树中\(x,y\)的路径上

P6329 【模板】点分树 | 震波

对每个点开深度线段树存子树权值,暴力跳\(fa[]\)统计即可

对于要刨掉的\(x\)所属子树\(p\),再开一棵线段树维护子树\(p\)\(fa[p]\)的距离

边分治

把重心换成边即可,记得单点度数过大时要拆点

P4565 [CTSC2018]暴力写挂

一个常见思路:多树统计,用虚树DP

路径问题,考虑点分治或边分治,这里使用边分治

统计左子树和右子树之间的最大权,发现原树的\(depth(LCA(x,y))\)不好处理,考虑对贡献进行转化

\(\displaystyle depth(x)+depth(y)-(depth(LCA(x,y)+depth'(LCA'(x,y)))\)

\(\displaystyle =\frac 1 2 *dist(x,y)+\frac 1 2*(dep(x)+dep(y))-depth'(LCA'(x,y))\)

此时,原树的贡献可以完全放入\(x,y\)两个点内(\(\displaystyle \frac 1 2*(dis[x]+dep[x])\)),将它们挂到虚树上,DP可得答案

时间复杂度\(O(n\log ^2 n)\)

细节

1、为什么不用点分治?

点分治会产生若干棵子树,虚树DP很难\(O(n)\)解决

2、建虚树时存的\(lca\),不要算它的权值

3、猜猜我调了3h+,发现问题在哪,原来是\(fa[N][20]\)倍增数组开小了啊,我tm真是个sb

posted @ 2024-11-02 17:09  Zhone_lb  阅读(16)  评论(0)    收藏  举报