CF1060E Sergey and Subway

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\n",ans);	
	return 0;
}
 
posted @ 2020-11-30 13:59  ke_xin  阅读(40)  评论(0编辑  收藏  举报