1. 程式人生 > 實用技巧 >CF1060E Sergey and Subway

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;
}