UR2 树上 GCD
【UR #2】树上 GCD
给定一棵树,用 \(\textrm{dist}(x,y)\),根节点为 \(1\)
对于每个 \(i\) 输出,求有多少对 \((u,v)\) 满足 \(f(u,v)=i\)
其中 \(x=\textrm{LCA}(u,v),f(u,v)=\gcd(\textrm{dist}(u,x),\textrm{dist}(v,x))\)
\(n\le 2\times 10^5\)
Solution
先转换为至少,然后枚举 \(\rm LCA\) 为 \(x\),对此树进行长链剖分,对于每个点分别统计贡献:
- 轻儿子的贡献。
- 轻儿子 + 重儿子的贡献。
Part 1 通过经典的容斥解决,计算至少的部分通过调和级数保证复杂度,总体复杂度为 \(\mathcal O(n\log n)\)
对于 Part2,我们设轻儿子中最长路径为 \(\textrm{mx}\),则显然可以被贡献的约数 \(d\) 不超过 \(\textrm{mx}\),且 \(\sum \textrm{mx}\le n\)
于是可以枚举 \(d\) 并考虑统计答案,这里根号分治:
- 若 \(d\ge \sqrt{n}\),则暴力枚举 \(kd\) 即 \(d\) 的倍数。
- 否则预处理。
其中第二部分如果在模 \(\{2,3,4...\sqrt{n}\}\) 意义下考虑是难以解决的,我们不妨考虑设 \(f_{x,d}\) 表示 \(x\) 子树内所有距离 \(x\) 为 \(d\) 的倍数的点的个数,则显然我们可以枚举 \(x\) 的重儿子 \(u\) 的所有 \(d\) 级儿子并统计 \(f_{v,d}\) 的和即可。
反过来,一个 \(f_{v,d}\) 可以贡献至其 \(d\) 级祖先处(需要特判掉轻儿子的情况)
我们的瓶颈在于计算点 \(x\) 的 \(d\) 级祖先,不难注意到 \(d\) 为 \(1\sim \sqrt{n}\) 所以可以直接预处理。
总体复杂度 \(\mathcal O(n\sqrt{n})\)
空间复杂度乍一看是 \(\mathcal O(n\sqrt{n})\) 的,然而是可以做到 \(\mathcal O(n)\) 的,空间开销来源于 \(d\le \sqrt{n}\) 的 Part,逐个 \(d\) 解决即可,空间复杂度即降低为 \(O(n)\)
调试细节:
- 注意长链剖分的时候上界对应
<
- 添加 \(d\) 级祖先贡献时的条件为 \(d-1\) 级不为轻链顶端。
为啥我把块大小设为 \(n^{\frac{1}{4}}\) 跑得最快啊,想不通。