点分治,很模板的做法,不说什么了吧。
就是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;
}