设
f
[
x
]
[
i
]
f[x][i]
f[x][i] 表示点
x
x
x 的子树内与点
x
x
x 距离为
i
i
i 的点数,转移显然为:
f
[
x
]
[
i
]
=
∑
y
∈
c
h
i
l
d
r
e
n
[
x
]
f
[
y
]
[
i
−
1
]
f[x][i] =\sum\limits_{y \in children[x]} f[y][i - 1]
f[x][i]=y∈children[x]∑f[y][i−1]
设
g
[
x
]
[
i
]
g[x][i]
g[x][i] 表示在点
x
x
x 的子树内选取两点,满足两点到其
L
C
A
LCA
LCA 的距离为
d
d
d,
L
C
A
LCA
LCA 到点
x
x
x 的距离为
d
−
i
d - i
d−i 的方案数,转移只要额外考虑
L
C
A
LCA
LCA 为点
x
x
x (
d
=
i
d = i
d=i)的情况,其余情况可以由子节点的
g
g
g 得到,即:
g
[
x
]
[
i
]
=
∑
y
∈
c
h
i
l
d
r
e
n
[
x
]
(
g
[
y
]
[
i
+
1
]
+
f
′
[
x
]
[
i
]
×
f
[
y
]
[
i
−
1
]
)
(
f
′
,
g
′
表
示
处
理
y
这
棵
子
树
前
f
的
值
)
g[x][i] = \sum \limits_{y \in children[x]}(g[y][i + 1] + f'[x][i] \times f[y][i - 1])(f',g'表示处理 y这棵子树前 f 的值)
g[x][i]=y∈children[x]∑(g[y][i+1]+f′[x][i]×f[y][i−1])(f′,g′表示处理y这棵子树前f的值)
则答案
a
n
s
=
∑
x
=
1
n
∑
y
∈
c
h
i
l
d
r
e
n
[
x
]
∑
i
(
f
′
[
x
]
i
]
×
g
[
y
]
[
i
+
1
]
+
g
′
[
x
]
[
i
]
×
f
[
y
]
[
i
−
1
]
)
ans = \sum \limits_{x = 1}^{n}\sum \limits_{y \in children[x]}\sum \limits_{i}(f'[x]i] \times g[y][i + 1] + g'[x][i] \times f[y][i - 1])
ans=x=1∑ny∈children[x]∑i∑(f′[x]i]×g[y][i+1]+g′[x][i]×f[y][i−1])
时间复杂度
O
(
n
2
)
O(n^2)
O(n2)。
考虑用类似
d
s
u
o
n
t
r
e
e
dsu\ on\ tree
dsuontree 的思想优化,保存长链上子节点的信息(相当于将子节点的
f
f
f 右移,
g
g
g 左移),其余节点暴力计算,时间复杂度相当于树中所有长链的长度之和,即为
O
(
n
)
O(n)
O(n)。
空间问题用指针分配即可,具体参考实现。
Code
#include<algorithm>#include<iostream>#include<cstring>#include<cstdlib>#include<cstdio>#include<cctype>#include<cmath>#include<ctime>template<classT>inlinevoidread(T &res){char ch;while(ch =getchar(),!isdigit(ch));
res = ch ^48;while(ch =getchar(),isdigit(ch))
res = res *10+ ch -48;}typedeflonglong ll;constint N =1e5+5;constint M =1e6+5;int n, mx[N], son[N];
ll ans, tmp[M],*f[N],*g[N],*now = tmp + N;struct Edge
{int to; Edge *nxt;}p[N <<1],*lst[N],*P = p;inlinevoidLink(int x,int y){(++P)->nxt = lst[x]; lst[x]= P; P->to = y;(++P)->nxt = lst[y]; lst[y]= P; P->to = x;}inlinevoidCreate(int x){
f[x]= now;
now += mx[x]<<1|1;
g[x]= now;
now += mx[x]<<1|1;}inlinevoidDfs1(int x,int Fa){for(Edge *e = lst[x]; e; e = e->nxt){int y = e->to;if(y == Fa)continue;Dfs1(y, x);if(mx[y]+1> mx[x]){
mx[x]= mx[y]+1;
son[x]= y;}}}inlinevoidDfs2(int x,int Fa){if(son[x]){
f[son[x]]= f[x]+1;
g[son[x]]= g[x]-1;Dfs2(son[x], x);}
f[x][0]=1;
ans += g[x][0];for(Edge *e = lst[x]; e; e = e->nxt){int y = e->to;if(y == son[x]|| y == Fa)continue;Create(y);Dfs2(y, x);for(int i =0; i <= mx[y];++i){
ans += g[x][i +1]* f[y][i];if(i)
ans += f[x][i -1]* g[y][i];}for(int i =0; i <= mx[y];++i){
g[x][i +1]+= f[y][i]* f[x][i +1];
f[x][i +1]+= f[y][i];if(i)
g[x][i -1]+= g[y][i];}}}intmain(){read(n);for(int i =1, x, y; i < n;++i){read(x);read(y);Link(x, y);}Dfs1(1,0);Create(1);Dfs2(1,0);
std::cout << ans << std::endl;}