学了这么久的点分治 / 点分树,感觉自己还是只会做点裸题……这都要国赛了感觉自己吃枣药丸。
CSAcademy Round 10 Yury's Tree
题意
给定一棵 (n) 个点的树,每条边有一个边权。接下来有 (m) 次操作分为以下两种:
1 u
查询 (u) 号点的价值。2 x y z
表示对于 (x) 子树的所有点 (u) ,如果 (u) 到 (x) 的路径上的边权全都大于等于 (y) ,就给 (u) 的价值加上 (z) 。(n,m le 3 imes 10^5 , TL = 1.5s) 。原题范围 (n,m le 10^5,TL = 4s)
题解
原题的做法是个不太优美的根号算法,事实上这个题是存在 (log) 级别做法的。
首先假设修改全部在询问之前。注意到这里你需要保证路径最大值大于等于某个数,因此可以考虑一下点分治。分治到当前分治重心的时候,把分治重心沿原树的父亲往上爬,直到遇到上一分治重心或根节点,把这条路径上的有效修改操作提取出来。某一次查询的点 (u) 如果可以被修改操作 ((x,y,z)) 贡献到,那么 (u) 到分治重心的最大边权 (w) 就要小于等于 (y)。这可以很容易地统计出来。
我们再加上时间这一维,就只要拿一个树状数组维护就行了,复杂度 (O(n log^2 n)) 。
总结
对于有根树上的一些问题,思路也不要被局限,点分治也是一个很好的角度;对于树上的某些单点查询,可以考虑修改对查询的贡献,而不是把整个值维护出来。
一个经典问题
题意
给出一棵 (n) 个点的有根树,每个结点上有一个一次多项式。求每个结点到根的多项式乘积的和。
(n le 10^5) 。
题解
树上路径问题,可以继续考虑点分治。点分治之后,假如求出了当前分治重心到根节点的多项式乘积,那么接下来只需要对于每一个不包含根节点的子树,计算以这个子树的根节点为新的根,关于这个子树的一个子问题即可。最后加起来统一卷积。
考虑如何求出这条路径的多项式乘积,直接暴力分治 ( ext{FFT}) 是 (O(n log^2 n)) 的,加上点分治就是 (O(n log^3 n)) ,不太能过。注意到其实这个分治 ( ext{FFT}) 有大量的重复计算,因此优化可以从这里下手。我们只需要不断地找到该路径上的下一个点分中心,就可以直接得到下一个点分中心到根的路径的乘积,这样可以得到 (O(log n)) 个多项式,其中第 (i) 个多项式长度级别不会超过 (frac{n}{2^i})。显然把他们卷起来的时间复杂度是 (O(n log n)),因此总复杂度降到了 (O(n log^2 n)) 。
Codeforces 936E Iqea
题意
有一间房子由 (n) 个格子组成,第 (i) 个格子位于坐标 ((x_i,y_i)) ,保证所有属于房子的格子是四连通的,同时保证所有不属于房子的格子也是四连通的。
房子里有好多的橘猫。橘猫想吃东西。接下来会发生 (m) 个事件,第 (i) 个事件可以用三个数 (ty,x,y) 表示。
若 (ty = 1) 则表示坐标 ((x,y)) 处出现了一大碗猫粮,猫粮是吃不完的。
若 (ty = 2) 则表示坐标 ((x,y)) 处出现了一只橘猫,他会走向距离最近的猫粮去吃,注意猫不能走出房子。保证坐标都在房子内。
对于每个 (ty = 2) 的事件,橘猫想让你告诉他们,距离最近的猫粮距离是多少。
(n,m,x_i,y_i le 3 imes 10^5) 。
题解
由于属于房子和不属于房子的格子都是四联通的,因此联通部分不存在环。
如果把所有垂直方向上相邻的格子缩成一个点,那么这样就形成了一棵树。考虑一只橘猫和一碗猫粮在枚举了相遇的那个节点之后,应该怎么算距离。可以发现,一定是先找到对应的到这个节点的最短路径,然后在这个节点上走完剩下的路。这样的话,只要在每个分治重心存下这个分治区域中,所有的猫粮到该分治重心的最短距离,以及到了之后的位置,询问时就可以到每个分治中心去查询了。由于到每个分治重心处还需要 (O(log n)) 的代价维护,因此时间复杂度 (O(n log^2 n)) 。
总结
模型转化是这道题的一大核心;对于树上动态维护一个点到一个点集的最短路,可以考虑用点分树来维护;可以把分治重心当做类似中转站的处理点。
Luogu P5311
题意
给定一棵 (n) 个点的树,每个节点有一个颜色。(q) 询问从 (x) 出发,只经过编号在 ([l,r]) 中的点,所能到达的点的颜色种数。
(n,q le 10^5) 。
题解
建出点分树,一个很重要的性质是,对于询问 ((l,r,x)) 中 (x) 所在的一个连通块,必定完全包含在点分树上某一个节点 (p) 的子树里,满足 (p in [l,r])。证明可以考虑,如果不存在这样的 (p) ,那么这个联通块必然会被某个分治重心分开成若干个联通块。
接下来我们只要沿着点分树向上爬,就不难找到这个 (p) 。对于当前分治重心,求出每个点到这个分治重心的路径编号最大最小值,问题就可以化为,给定若干个区间,每个区间有一种颜色,每次询问会给定一个区间 ([l,r]) ,求被 ([l,r]) 完整包含的区间颜色种数。不难发现只需要离线树状数组扫一遍就行了,复杂度 (O(n log^ 2 n)) 。
总结
题目的难点主要在前面的性质发现。思路可能要有意识地往这上面靠。