#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define maxn 40000
using namespace std;
struct eg
{
int to,v,nxt;
}b[maxn];
int head[maxn],tot=0,f[maxn],sz[maxn],vis[maxn],d[maxn]={0},ans,root,sum,t1[5];
int gcd(int x,int y){return y?gcd(y,x%y):x;}
void link(int x,int y,int z)
{
b[++tot].nxt=head[x];
b[tot].to=y;
b[tot].v=z;
head[x]=tot;
}
void getroot(int u,int fa)
{
sz[u]=1,f[u]=0;
for (int i=head[u];i;i=b[i].nxt)
{
int t=b[i].to;
if (vis[t]||t==fa) continue;
getroot(t,u);
sz[u]+=sz[t];
f[u]=max(f[u],sz[t]);
}
f[u]=max(f[u],sum-sz[u]);
if (f[root]>f[u]) root=u;
}
void getdeep(int x,int fa)
{
t1[d[x]]++;
for (int i=head[x];i;i=b[i].nxt)
{
int t=b[i].to;
if (vis[t]||t==fa) continue;
d[t]=(d[x]+b[i].v)%3;
getdeep(t,x);
}
}
int cal(int x,int vv)
{
d[x]=vv%3;
t1[0]=t1[1]=t1[2]=0;
getdeep(x,0);
return t1[1]*t1[2]*2+t1[0]*t1[0];
}
void work(int x)
{
ans+=cal(x,0);
vis[x]=1;
for (int i=head[x];i;i=b[i].nxt)
{
int t=b[i].to;
if (vis[t]) continue;
ans-=cal(t,b[i].v);
sum=sz[t];
root=0;
getroot(t,0);
work(root);
}
}
int main()
{
int n;
scanf ("%d",&n);
for (int i=1;i<n;++i)
{
int x,y,w;
scanf ("%d%d%d",&x,&y,&w);
link(x,y,w);
link(y,x,w);
}
root=0;f[0]=n,sum=n;
getroot(1,0);
work(root);
int l=gcd(ans,n*n);
cout<<(ans/l)<<"/"<<(n*n/l);
return 0;
}
点分治板子
然而想那个 t1[1]*t1[2]*2+t1[0]*t1[0]想了好久
就是最基本的组合方法 毕竟(2,5)和(5,2)可是要算两次的
画画图就好了
(不要像我一样盯着大佬们的显然可得懵逼23333)