CF1060E Sergey and Subway
统计边的贡献
先不考虑题中的重连边,显然求得就是树上任意两点距离和,按边计贡献,(dfs)一遍搞个(siz)就行
然后对于重连边,显然是偶数距离的会都重复计算,所以都要除以二,答案就是 偶数距离的/2+奇数距离的
然后可以方便先计算树上任意两点距离和,然后减去奇数距离的
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=200005;
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
int n;
int hd[N],to[N<<1],nxt[N<<1],tot;
inline void add(int x,int y) {
to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
}
int dep[N],siz[N];
void dfs(int x,int f) {
siz[x]=1;
dep[x]=dep[f]+1;
for(int i=hd[x];i;i=nxt[i]) {
int y=to[i];
if(y==f) continue;
dfs(y,x);
siz[x]+=siz[y];
}
}
int main() {
n=read();
for(int i=1;i<n;i++) {
int u=read(),v=read();
add(u,v);add(v,u);
}
dfs(1,0);
ll ans=0,c=0;//c是奇数点的数量
for(int i=1;i<=n;i++) {
ans+=(ll)siz[i]*(n-siz[i]);
if(dep[i]&1) c++;
}
ll k=c*(n-c);
ans=(ans-k)/2+k;
printf("%lld
",ans);
return 0;
}