点分治、动态点分治

点分治【算法简介】

点分治是选择一个点将无根树变成有根树,然后递归处理每一棵以根节点的儿子为根的子树

为了优化时间复杂度,我们将重心作为选择的点,这样可以证明递归的深度最坏为O(logn),在链上取到最值

然后我们就需要考虑对于当前的重心u,如何计算贡献,一般来说,我们solve到每一个节点的时候,计算的是跨过这个点的来自两个子树的带来的贡献

有如下的计算方法:

1.总答案-不符合条件的答案

具体的,就是先计算一个点所有子节点之间的贡献,然后再减去来自同一个子树的部分即可

2.用当前子树和之前走过的部分来计算答案(更常用

每次走完一个子树把有用的信息存下来,然后在走下一个子树的时候计算和记录的之前的信息贡献即可

具体的实现就看看题目的代码吧

【例题1】poj1741 Tree

求树上长度小于等于k的路径条数 sol.

【练习1】bzoj2152 聪聪可可

求树上长度为3的倍数的路径数 sol.

【例题2】bzoj2599 Race

求树上权值和为k的路径包含的最少边数 sol.

【习题1】bzoj4738 汽水

求一条路径,平均值最接近k sol.

【习题2】bzoj4016 [FJOI2014]最短路径树问题

在最短路径树上,最长的包含K个点的简单路径长度为多长?长度为该最长长度的不同路径有多少条?sol.

【习题3】bzoj4182 Shopping

点分治+dfs序+多重背包dp(单调队列优化)sol.

动态点分治【算法简介】

动态点分治就是对于一些信息可以进行修改,仍然是要去求一些和路径相关的答案

我们可以利用一些数据结构去实现较为快速的查询和修改,然后再通过点分树来降低修改和查询的次数到log级别

那么什么是点分树呢?或许它可以算一种数据结构,十分小清新

点分树顾名思义,就是在点分治过程中生成的一棵树,我们只需要把新的计算出的root和之前的一个root(也就是当前solve的u节点)连上边,然后把子树的信息记录在当前的点里

这样我们就得到了一棵深度为logn的树,可以用于实现树上的一些问题了

但是这样就够了么? 考虑我们计算贡献的时候,会算重复一些东西

看一个例子:我们计算到u点距离不超过k的点权和,对于当前一个点u可以通过记录的子树信息算出距离为k的部分,但是u在点分树上父亲的部分就没有计算到

所以我们要不断的向上跳fa,然后计算fa记录的距离为k-dis(fa,u)的部分不断累加

但是这样我们就算重了,u子树内也可能存在距离fa为d-dis(fa,u)的节点

所以对于每个点u,我们要记录的是到u的距离为i的和sum[u][i],以及到u的fa的距离为i的部分sumfa[u][i]

这时候就需要利用一些数据结构去维护,比如线段树啊,树状数组之类的

由于每个点可能都需要记录这样的信息,所以一般都会用到动态开点和标记可持久化的技术

点分树

【例题1】P3345 [ZJOI2015]幻想乡战略游戏

给定一个树,要求如下操作

每次修改一个点权之后,询问选择树上哪一个点作为补给站u可以使dis(u,i)*vi的和最小  sol.

点分树+线段树/树状数组

【例题2】P6329 【模板】点分树 | 震波

给一个树,要求你支持如下操作

1.修改某个点的点权 2.询问到某个点的距离小于等于k的点权和  sol.

【习题2】BZOJ4372烁烁的游戏

和上面的例题十分相似,给一个树,要求你支持如下操作

1.查询某个点权 2.修改到某个点距离小于等于k的点      sol.

点分树+带删除的优先级队列

第一次写待删除的优先级队列

【例题3】P2056 [ZJOI2007]捉迷藏

给一个树,初始点权全部为0,要求你支持如下操作

1.把一个点的点权异或上1   2.查询树上点权为0的两点之间距离最大的距离 sol.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值