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\),对此树进行长链剖分,对于每个点分别统计贡献:

  1. 轻儿子的贡献。
  2. 轻儿子 + 重儿子的贡献。

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)\)

调试细节:

  1. 注意长链剖分的时候上界对应 <
  2. 添加 \(d\) 级祖先贡献时的条件为 \(d-1\) 级不为轻链顶端。

为啥我把块大小设为 \(n^{\frac{1}{4}}\) 跑得最快啊,想不通。

posted @ 2021-03-05 08:05  Soulist  阅读(195)  评论(0编辑  收藏  举报