bzoj 2152 聪明可可

Description

聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃、两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已经玩儿腻了这种低智商的游戏。他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画n个“点”,并用n-1条“边”把这n个“点”恰好连通(其实这就是一棵树)。并且每条“边”上都有一个数。接下来由聪聪和可可分别随即选一个点(当然他们选点时是看不到这棵树的),如果两个点之间所有边上数的和加起来恰好是3的倍数,则判聪聪赢,否则可可赢。聪聪非常爱思考问题,在每次游戏后都会仔细研究这棵树,希望知道对于这张图自己的获胜概率是多少。现请你帮忙求出这个值以验证聪聪的答案是否正确。

Input

输入的第1行包含1个正整数n。后面n-1行,每行3个整数x、y、w,表示x号点和y号点之间有一条边,上面的数是w。

Output

以即约分数形式输出这个概率(即“a/b”的形式,其中a和b必须互质。如果概率为1,输出“1/1”)。

Sample Input

5
1 2 1
1 3 2
1 4 1
2 5 3

Sample Output

13/25
【样例说明】
13组点对分别是(1,1) (2,2) (2,3) (2,5) (3,2) (3,3) (3,4) (3,5) (4,3) (4,4) (5,2) (5,3) (5,5)。

【数据规模】
对于100%的数据,n<=20000。
 
思路: 树的点分治,比较基础。 
 1 #include<bits/stdc++.h>
 2 using namespace std;  
 3 #define R register int
 4 #define rep(i,a,b) for(R i=a;i<=b;i++)  
 5 #define Rep(i,a,b) for(R i=a;i>=b;i--)  
 6 #define rp(i,x)    for(R i=H[x];i!=-1;i=E[i].nt) 
 7 #define ms(i,a)    memset(a,i,sizeof(a)) 
 8 #define gc()       getchar() 
 9 #define LL         long long 
10 template<class T>void read(T &x){
11     x=0; char c=0; 
12     while (!isdigit(c)) c=gc(); 
13     while (isdigit(c)) x=x*10+(c^48),c=gc();  
14 }
15 int const N=20000+3; 
16 struct Edge{
17     int to,nt,w;  
18 }E[N<<1]; 
19 int n,H[N],cnt,vis[N],ans,sz[N];    
20 void add(int a,int b,int c){
21     E[cnt]=(Edge){b,H[a],c}; H[a]=cnt++;  
22 }
23 int getsize(int x,int fa){
24     sz[x]=1;  
25     rp(i,x){
26         int v=E[i].to;  
27         if(v==fa || vis[v]) continue;  
28         sz[x]+=getsize(v,x);
29     }
30     return sz[x];  
31 }
32 int findroot(int x,int fa,int sum){
33     int num=0,tot=1;  
34     rp(i,x){
35         int v=E[i].to; 
36         if(v==fa || vis[v]) continue;  
37         int t=findroot(v,x,sum);  
38         if(t) return t;
39         num=max(num,sz[v]);
40         tot+=sz[v];      
41     }
42     num=max(num,sum-tot);  
43     if(num*2<=sum)  return x; 
44     else return 0;
45 }
46 void dfs(int x,int fa,int d,int *tmp){
47     tmp[d]++;  
48     rp(i,x){
49         int v=E[i].to;  
50         if(v==fa || vis[v]) continue;  
51         dfs(v,x,(d+E[i].w)%3,tmp);  
52     }
53 }
54 void solve(int x){
55     int num[3];ms(0,num);  
56     rp(i,x){
57         int v=E[i].to;  
58         if(vis[v]) continue;  
59         int z=findroot(v,0,getsize(v,0)); 
60         int tmp[3];ms(0,tmp);  
61         dfs(v,0,E[i].w%3,tmp);
62         ans+=2*tmp[0];  
63         rep(j,0,2) ans+=2*num[(3-j)%3]*tmp[j];  
64         rep(j,0,2) num[j]+=tmp[j];  
65         vis[z]=1;  
66         solve(z);  
67     } 
68     ans++;
69 }   
70 int gcd(int x,int y){return y? gcd(y,x%y): x;} 
71 int main(){
72     read(n); ms(-1,H);  
73     rep(i,1,n-1){
74         int x,y,z; read(x); read(y); read(z);  
75         add(x,y,z); add(y,x,z);  
76     }
77     int z=findroot(1,0,getsize(1,0));  
78     vis[z]=1;  
79     solve(z);   
80     int g=gcd(ans,n*n);  
81     printf("%d/%d\n",ans/g,n*n/g); 
82     return 0;   
83 }
View Code

 

posted @ 2019-01-17 23:26  zjxxcn  阅读(140)  评论(0编辑  收藏  举报