内存诚可贵,效率价更高,若为码长故,二者皆可抛。
本着珍爱生命,远离边分的原则,我果断选择了点分。
听说此题树形DP可过?算了懒得管。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=20000+5;
const int inf=1e9;
struct Edge{int to,next,v;}e[N<<1];
int head[N],cnt;
void ins(int u,int v,int w){
e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].v=w;
}
int siz[N],root,dist[N],tot,lim,sz;
int rest[3],ans;
bool vis[N];
void findroot(int u,int fa){
siz[u]=1;int tmp=0;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(v==fa||vis[v])continue;
findroot(v,u);
siz[u]+=siz[v];
tmp=max(tmp,siz[v]);
}
tmp=max(tmp,sz-siz[u]);
if(tmp<lim)lim=tmp,root=u;
}
void dfs(int u,int fa,int d){
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(v==fa||vis[v])continue;
dist[++tot]=d+e[i].v;
dfs(v,u,d+e[i].v);
}
}
void calc(){
memset(rest,0,sizeof(rest));
for(int i=1;i<=tot;i++)
rest[dist[i]%3]++;
}
void divide(int u){
lim=inf;findroot(u,0);
tot=0; dfs(root,0,0); calc(); ans+=rest[0]*2;
int A=rest[0]*(rest[0]-1)+rest[1]*rest[2]*2,B=0;
for(int i=head[root];i;i=e[i].next){
int v=e[i].to;
if(vis[v])continue;
tot=0; dfs(v,root,e[i].v);dist[++tot]=e[i].v; calc(); B+=rest[0]*(rest[0]-1)+rest[1]*rest[2]*2;
}
ans+=A-B;
vis[root]=true;
for(int i=head[root];i;i=e[i].next){
int v=e[i].to;
if(vis[v])continue;
sz=siz[v];
divide(v);
}
}
int gcd(int a,int b){
return (!b)?a:gcd(b,a%b);
}
int main(){
int n;scanf("%d",&n);int u,v,w;sz=n;
for(int i=1;i<sz;i++){
scanf("%d%d%d",&u,&v,&w);
ins(u,v,w);ins(v,u,w);
}
divide(1);ans+=n;
int mo=n*n;
int tmp=gcd(ans,mo);
printf("%d/%d",ans/tmp,mo/tmp);
return 0;
}