P2634 [国家集训队]聪聪可可

P2634 [国家集训队]聪聪可可

点分治,很模板的做法,不说什么了吧。
就是calc的方法再多说一句。
ans加的应该是图1红线的情况,但是会出现图2的多余情况,要减掉

#include<bits/stdc++.h>
using namespace std;
const int N=20005;
struct edge {
	int nxt,to,val;
} e[N<<1];
int head[N],num_edge;
void add(int from,int to,int val) {
	++num_edge;
	e[num_edge].nxt=head[from];
	e[num_edge].to=to;
	e[num_edge].val=val;
	head[from]=num_edge;
}
int n,siz[N],rt,mn,d[N],sum;
bool used[N];
void getrt(int u,int fa) {
	int mx=0;siz[u]=1;
	for(int i=head[u]; i; i=e[i].nxt) {
		int v=e[i].to;
		if(used[v]||v==fa)continue;
		getrt(v,u);
		siz[u]+=siz[v];
		mx=max(mx,siz[v]);
	}
	mx=max(mx,sum-siz[u]);
	if(mx<mn)mn=mx,rt=u;
}
int a[3],ans;
void getdis(int u,int fa) {
	d[u]%=3;++a[d[u]];
	for(int i=head[u]; i; i=e[i].nxt) {
		int v=e[i].to;
		if(v==fa||used[v])continue;
		d[v]=d[u]+e[i].val;
		getdis(v,u);
	}

}
int calc(int u,int dd) {
	a[1]=a[2]=a[0]=0;
	d[u]=dd%3;
	getdis(u,0);
	return a[0]*a[0]+a[1]*a[2]+a[2]*a[1];
}
void solve(int u) {
	ans+=calc(u,0);
	used[u]=true;
	for(int i=head[u]; i; i=e[i].nxt) {
		int v=e[i].to;
		if(used[v])continue;
		ans-=calc(v,e[i].val);
		mn=n;
		sum=siz[v];
		getrt(v,u);
		solve(rt);
	}
}
int main() {
	scanf("%d",&n);
	for(int i=1,x,y,w; i<n; ++i) {
		scanf("%d%d%d",&x,&y,&w);w%=3;
		add(x,y,w);add(y,x,w);
	}
	sum=n;mn=n;getrt(1,0);
	solve(rt);
	int t=__gcd(ans,n*n);
	printf("%d/%d\n",ans/t,n*n/t);
	return 0;
}
原文地址:https://www.cnblogs.com/zzctommy/p/12321173.html