1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int N=20010;
 5 int t[5],head[N],son[N],f[N],d[N],root,ans,n,sum,cnt;
 6 bool vis[N];
 7 struct ee{int to,next,v;}e[N*2];
 8 void insert(int u,int v,int w){
 9     e[++cnt].to=v;e[cnt].next=head[u];e[cnt].v=w;head[u]=cnt;
10 }
11  
12 int gcd(int a1,int a2)
13 {
14     int a3=a1%a2;
15     for(;a3;)
16       {
17         a1=a2;
18         a2=a3;
19         a3=a1%a2;
20       }
21     return a2;
22 }
23  
24 void getroot(int x,int fa){
25     son[x]=1;f[x]=0;
26     for (int i=head[x];i;i=e[i].next){
27         int v=e[i].to;
28         if (!vis[v]&&v!=fa){
29             getroot(v,x);
30             son[x]+=son[v];
31             f[x]=max(f[x],son[v]);
32         }
33     }
34     f[x]=max(f[x],sum-son[x]);
35     if (f[root]>f[x])root=x;
36 }
37  
38 void getdeep(int x,int fa){
39     t[d[x]]++;
40     for (int i=head[x];i;i=e[i].next){
41         int v=e[i].to;
42         if (v!=fa&&!vis[v]){
43             d[v]=(d[x]+e[i].v)%3;
44             getdeep(v,x);
45         }
46     }
47 }
48  
49 int cal(int x,int now){
50     t[0]=t[1]=t[2]=0;
51     d[x]=now;
52     getdeep(x,0);
53     return t[1]*t[2]*2+t[0]*t[0];
54 }
55  
56 void work(int x){
57     ans+=cal(x,0);
58     vis[x]=1;
59     for (int i=head[x];i;i=e[i].next){
60         int v=e[i].to;
61         if (!vis[v]) {
62             ans-=cal(v,e[i].v);
63             root=0;sum=son[v];
64             getroot(v,0);
65             work(root);
66         }
67     }
68 }
69  
70 int main(){
71     scanf("%d",&n);
72     int u,v,w;
73     for (int i=1;i<n;i++){
74         scanf("%d%d%d",&u,&v,&w);
75         w%=3;
76         insert(u,v,w);
77         insert(v,u,w);
78     }
79     f[0]=sum=n;
80     root=0;
81     getroot(1,0);
82     work(root);
83     int t=gcd(ans,n*n);
84     printf("%d/%d",ans/t,n*n/t);
85 }

树的点分治  首先找树的重心,把根节点设为树的重心。然后进行点分治(就是从根开始,看经过根的方案数,在把根删掉,求每棵子树)。

posted on 2016-03-20 17:41  xiyuedong  阅读(148)  评论(0编辑  收藏  举报