[国家集训队]聪聪可可
求出\(mod\ 3=0\)的路径条数,乘\(2\)加\(n\)除以\(n^2\)就是答案
点分治就好了
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 20005
#define re register
#define inf 99999999
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
int x=0;char c=getchar();while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
struct E{int v,nxt,w;}e[maxn<<1];
int n,m,num,tot,S,now,rt;LL ans=0;
int head[maxn],vis[maxn],d[maxn],tax[3],sum[maxn],mx[maxn];
inline void add(int x,int y,int z) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;e[num].w=z;}
inline LL gcd(LL a,LL b) {if(!b) return a;return gcd(b,a%b);}
void getroot(int x,int fa) {
sum[x]=1,mx[x]=0;
for(re int i=head[x];i;i=e[i].nxt) {
if(vis[e[i].v]||e[i].v==fa) continue;
getroot(e[i].v,x);
sum[x]+=sum[e[i].v],mx[x]=max(mx[x],sum[e[i].v]);
}
mx[x]=max(mx[x],S-sum[x]);
if(mx[x]<now) now=mx[x],rt=x;
}
void getdis(int x,int fa,int L) {
d[++tot]=(L%3);
for(re int i=head[x];i;i=e[i].nxt) {
if(vis[e[i].v]||e[i].v==fa) continue;
getdis(e[i].v,x,L+e[i].w);
}
}
void dfs(int x) {
vis[x]=1;
for(re int i=head[x];i;i=e[i].nxt) {
if(vis[e[i].v]) continue;
tot=0;getdis(e[i].v,0,e[i].w);
for(re int j=1;j<=tot;j++) ans+=(d[j]==0),ans+=tax[(3-d[j])%3];
for(re int j=1;j<=tot;j++) tax[d[j]]++;
}
tax[0]=tax[1]=tax[2]=0;
for(re int i=head[x];i;i=e[i].nxt) {
if(vis[e[i].v]) continue;
S=sum[e[i].v],now=inf,getroot(e[i].v,0),dfs(rt);
}
}
int main() {
n=read();int x,y,z;
for(re int i=1;i<n;i++) x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z);
S=n,now=inf,getroot(1,0);dfs(rt);
ans*=2ll;ans+=n;
LL r=gcd(ans,(LL)n*(LL)n);
printf("%lld/%lld\n",ans/r,(LL)n*(LL)n/r);
return 0;
}