1 条题解
-
0
自动搬运
来自洛谷,原作者为

xht
好想爱这个世界啊搬运于
2025-08-24 22:15:28,当前版本为作者最后更新于2020-01-08 00:40:40,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
请到博客中查看
先考虑简单版的 怎么做。
设 为满足 在 的子树中且 的 的个数, 为满足 在 的子树中且 $d(\operatorname{lca}(x, y), x) = d(\operatorname{lca}(x, y), y) = d(\operatorname{lca}(x, y), i) + j$ 的无序数对 的个数。
有转移:
$$ans \leftarrow \sum_{x,y \in \operatorname{son}(i), x \ne y} f_{x,j-1} \times g_{y,j+1} $$$$g_{i,j} \leftarrow \sum_{x,y \in \operatorname{son}(i), x \ne y} f_{x,j-1} \times f_{y,j-1} $$$$g_{i,j} \leftarrow \sum_{x \in \operatorname{son}(i)} g_{x, j+1} $$$$f_{i,j} \leftarrow \sum_{x \in \operatorname{son}(i)} f_{x, j-1} $$显然这可以利用前缀和,或者说是所有儿子「向 合并」,做到 转移,总时间复杂度 。
注意到这里的信息都是以深度为下标的,那么可以利用长链剖分将复杂度降为均摊 ,总时间复杂度即可降为 。
在「直接继承重儿子的信息」时,需要用指针维护,具体见代码。
const int N = 1e5 + 7; int n, d[N], dep[N], son[N]; vi e[N]; ll *f[N], *g[N], p[N<<2], *o = p, ans; void dfs(int x, int fa) { d[x] = d[fa] + 1; for (auto y : e[x]) if (y != fa) { dfs(y, x); if (dep[y] > dep[son[x]]) son[x] = y; } dep[x] = dep[son[x]] + 1; } void dp(int x, int fa) { if (son[x]) f[son[x]] = f[x] + 1, g[son[x]] = g[x] - 1, dp(son[x], x); f[x][0] = 1, ans += g[x][0]; for (auto y : e[x]) if (y != fa && y != son[x]) { f[y] = o, o += dep[y] << 1, g[y] = o, o += dep[y] << 1; dp(y, x); for (int i = 0; i < dep[y]; i++) { if (i) ans += f[x][i-1] * g[y][i]; ans += g[x][i+1] * f[y][i]; } for (int i = 0; i < dep[y]; i++) { g[x][i+1] += f[x][i+1] * f[y][i]; if (i) g[x][i-1] += g[y][i]; f[x][i+1] += f[y][i]; } } } int main() { rd(n); for (int i = 1, x, y; i < n; i++) rd(x), rd(y), e[x].pb(y), e[y].pb(x); dfs(1, 0), f[1] = o, o += dep[1] << 1, g[1] = o, o += dep[1] << 1; dp(1, 0), print(ans); return 0; }
- 1
信息
- ID
- 4907
- 时间
- 1000ms
- 内存
- 500MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者