CF1060E Sergey and Subway
CF1060E Sergey and Subway
树上计数dp,考虑每条边的贡献,树上两点距离用深度与LCA表示
长度为2的两点间可以连一条边,所以对于任意两点
i
,
j
i,j
i,j,
d
i
s
2
i
,
j
=
⌈
d
i
s
i
,
j
/
2
⌉
=
(
d
i
s
i
,
j
+
(
d
i
s
i
,
j
%
2
=
=
1
)
)
/
2
dis2_{i,j}=\lceil dis_{i,j}/2 \rceil=(dis_{i,j}+ (dis_{i,j}\%2==1) )/2
dis2i,j=⌈disi,j/2⌉=(disi,j+(disi,j%2==1))/2
对于前半部分,我们要求原图上所有点对的距离,通过树形dp计算每条边对两端点集的贡献即可
对于后半部分,我们只需另外统计一下在原图中两点距离为奇数的点即可,对于任意两点:
d
i
s
i
,
j
=
d
e
p
i
+
d
e
p
j
−
2
∗
L
C
A
i
,
j
dis_{i,j}=dep_i+dep_j-2*LCA_{i,j}
disi,j=depi+depj−2∗LCAi,j 显然式子中的2*LCA不对奇偶产生影响,所以只需要处理出各点深度即可
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
vector<vector<int>> e(n+1);
for (int i=1;i<n;i++){
int a,b;
cin>>a>>b;
e[a].push_back(b);
e[b].push_back(a);
}
vector<int> dep(n+1);
vector<ll> sz(n+1);
ll ans=0,cnt=0;
function<void(int,int)> dfs=[&](int u,int fa){
sz[u]=1;
for (auto v:e[u]){
if (v==fa) continue;
dep[v]=dep[u]+1;
dfs(v,u);
sz[u]+=sz[v];
}
cnt+=(dep[u]%2==1);
ans+=sz[u]*(n-sz[u]);
};
dep[1]=1;
dfs(1,-1);
cout<<(ans+cnt*(n-cnt))/2;
return 0;
}