题解:点分治模板题
代码:
//BZOJ 2152
#include<iostream>
#include<cstring>
#include<cstdio>
#define MAXN 20010
#define MAXM 40010
#define cls(x) cnt[x][0]=cnt[x][1]=cnt[x][2]=0;
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
struct edges{
int to,pre,wgt;
}e[MAXM];int etop,h[MAXN],cnt[MAXN][3],ans[MAXN];
inline int add_edge(int u,int v,int w)
{
etop++;
e[etop].pre=h[u];
h[u]=etop;
e[etop].wgt=w;
e[etop].to=v;
return 0;
}
int rt,sz[MAXN],maxsz[MAXN];
bool vis[MAXN];int full_sz;
int get_rt(int x,int f)
{
sz[x]=1,maxsz[x]=0;
for(int i=h[x];i;i=e[i].pre)
if(!vis[e[i].to]&&e[i].to^f)
{
get_rt(e[i].to,x);
sz[x]+=sz[e[i].to];
if(sz[e[i].to]>maxsz[x])
maxsz[x]=sz[e[i].to];
}
maxsz[x]=max(maxsz[x],full_sz-sz[x]);
if(maxsz[x]<maxsz[rt]) rt=x;return 0;
}
int getsz(int x,int f)
{
sz[x]=1;
for(int i=h[x];i;i=e[i].pre)
if(!vis[e[i].to]&&e[i].to^f)
sz[x]+=getsz(e[i].to,x);
return sz[x];
}
int calc(int x,int f,int w)
{
cls(x);cnt[x][w]=1;
for(int i=h[x];i;i=e[i].pre)
if(!vis[e[i].to]&&e[i].to!=f)
{
calc(e[i].to,x,(w+e[i].wgt)%3);
for(int p=0;p<3;p++)
cnt[x][p]+=cnt[e[i].to][p];
}
return 0;
}
int dfs(int x)
{
get_rt(x,rt=0);getsz(x=rt,0);
vis[x]=true;cls(x);cnt[x][0]=ans[x]=1;
for(int i=h[x];i;i=e[i].pre)
if(!vis[e[i].to])
{
int y;calc(y=e[i].to,x,e[i].wgt);
for(int p=0;p<3;p++)
ans[x]+=cnt[x][p]*cnt[y][(3-p)%3];
for(int p=0;p<3;p++) cnt[x][p]+=cnt[y][p];
}
// debug(cnt[x][0])sp,debug(cnt[x][1])sp,debug(cnt[x][2])ln;
// debug(x)sp,debug(ans[x])ln;
for(int i=h[x];i;i=e[i].pre)
if(!vis[e[i].to])
{
full_sz=sz[e[i].to];
dfs(e[i].to);
}
return 0;
}
inline int gcd(int a,int b)
{
return a?gcd(b%a,a):b;
}
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<n;i++)
{
int u,v,w;scanf("%d%d%d",&u,&v,&w);w%=3;
add_edge(u,v,w);add_edge(v,u,w);
}
full_sz=n;maxsz[0]=n+1;dfs(1);
int a=0,b=n*n;
for(int i=1;i<=n;i++) a+=ans[i];a-=n;a<<=1;a+=n;
int d=gcd(a,b);printf("%d/%d\n",a/d,b/d);
return 0;
}