题目
题目描述
给定一棵有
n
n
n 个节点的无根树,树上的每个点有一个非负点权。
定义一条路径的价值为路径上的点权和 − - − 路径上的点权最大值。形式化地,设 v x v_x vx 为点 x x x 的权值,路径 X X X 的价值为 ∣ X ∣ |X| ∣X∣ ,则
∣ X ∣ = ∑ i ∈ X v i − max i ∈ X v i |X|=\sum_{i\in X}v_i-\max_{i\in X}v_i ∣X∣=i∈X∑vi−i∈Xmaxvi
给定参数 P P P ,我们想知道,有多少不同的树上简单路径,满足它的价值恰好是 P P P 的倍数。
数据范围与约定
n
≤
1
0
5
,
P
≤
1
0
7
n\le 10^5, P\le 10^7
n≤105,P≤107 。
思路
耿直的暴力
从每个点开始 b f s / d f s \tt{bfs/dfs} bfs/dfs 一次即可。复杂度 O ( n 2 ) \mathcal O(n^2) O(n2) 。
题外话:我打了倍增,成功地优化至 O ( n 2 log n ) \mathcal O(n^2\log n) O(n2logn) 。另一个同学 w x k \tt wxk wxk 打了树剖,优化至 O ( n 2 log 2 n ) \mathcal O(n^2\log^2n) O(n2log2n) 。
对于一条链
取链的中点 m m m ,只考虑经过 m m m 的路径。递归地计算不经过 m m m 的路径。
用两个指针,分别是从 m m m 到 l l l 、从 m m m 到 r r r ;用两个桶存储每个权值和出现的次数(模 P P P 意义下)。每次将最大值较小的指针移动一步。
总之,我们要求的就是——最大值在左边、最大值在右边这两种情况。在桶里直接找答案。
这是 O ( n log n ) \mathcal O(n\log n) O(nlogn) 的。
推广到树上
每次只考虑当前这个子树的根作为 l c a lca lca 。
还是用桶,换成用堆来求子树内的点。总之,目的还是求最大值在某个子树内的情况。
可惜的是,我们会错误的计算——我们没有避免取了两个同子树内的点。于是我们对子树再做一次,减掉这些多了的。
虽然我们的树高不稳定,但是对于随机数据,能做到 O ( n log 2 n ) \mathcal O(n\log^2 n) O(nlog2n) 。
加一点优化
套点分治即可。递归层数此时便稳定了,时间复杂度稳定在 O ( n log 2 n ) \mathcal O(n\log^2 n) O(nlog2n) 。
题外话:原题解中这样写——“感觉地球人都知道怎么做”。
看来我被剥夺了“球籍”
代码
原题解中这样写——“本套题中的代码量担当”。于是我放弃了。出题人的名称: v i s i t _ w o r l d \tt{visit\_world} visit_world 。