久未放晴的天空,|

TulipeNoire

园龄:1年10个月粉丝:18关注:17

「ZJOI2015」幻想乡战略游戏

先考虑怎么高效地找到重心。

我们从根节点(令其为 1)开始,每次往一个儿子走,要求以这个儿子为中心的的距离和更小(把式子写出来,容易知道这样的儿子要么没有,要么唯一),如果没有这样的儿子就结束。发现这个东西其实跟边权没有关系,因为写出来是一个 c(u,v)×(s12×sv) 的形式(s 是子树点权和),我们只关注它的正负,所以和边权无关。所以走的条件就是找一个满足 2×svs1 的儿子 v

怎么做呢?相当于找到 dfs 序最大的 x 使得 2×sxs1。把 s 放在线段树上 dfs 序对应位置维护,一个节点维护区间 s 最大值,查询的时候直接线段树上二分即可。

找到重心后,求答案是显然的,每一条边的贡献是边权乘上子树内/外点权和,用两棵线段树维护,一棵专门维护边权乘以子树内和,另一棵维护边权乘以子树外和。相当于维护区间 AiBi,操作是 A 的区间加,以及求区间 Ai×Bi,是很经典的。

至此我们用 O(n+qlog2n) 的时间复杂度解决了本题。


关于寻找重心,tx344 还阐述了一个更有意思(赤石,但是拓展性更强)的算法。

我们令 pi 表示 dfs 序为 i 的节点编号,那么我们按如下步骤构造一个序列:先写下 sp1p1,然后 sp2p2,如此一直写到 spnpn,观察发现这个序列的中位数(如果长度为偶数,则取左右两个都可)在重心的子树内。再从这个点出发向上二分。这个做法的优势在于,可以进行点权的子树加。如果使用一开始的方法,有两种截然不同的加法形式,可以求和,但是不便于求最值。对于这种方法,虽然还是线段树上二分,但我们要维护的是和,而非最值,所以把两个加法操作直接拼起来是没问题的,例题是 QOJ3307。时间复杂度与第一种方法是一样的。

本文作者:TulipeNoire

本文链接:https://www.cnblogs.com/TulipeNoire/p/18710586/P3345

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   TulipeNoire  阅读(11)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起