【bzoj2152】聪聪可可 点分治

【bzoj2152】聪聪可可

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。
 
询问多少点对之间路径和是3的倍数,这样就是模数什么的搞一搞就ok了。
 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #define N 20007
 7 #define inf 1000000009
 8 using namespace std;
 9 
10 int n,k;
11 int ans,id,total;
12 int siz[N],f[N],deep[N],dis[N],vis[N],num[4];
13 int cnt,head[N],next[N*2],rea[N*2],val[N*2];
14 
15 void add(int u,int v,int fee)
16 {
17     next[++cnt]=head[u];
18     head[u]=cnt;
19     rea[cnt]=v;
20     val[cnt]=fee;
21 }
22 void get_heart(int u,int fa)
23 {
24     siz[u]=1,f[u]=0;
25     for (int i=head[u];i!=-1;i=next[i])
26     {
27         int v=rea[i];
28         if (v==fa||vis[v])continue;
29         get_heart(v,u);
30         siz[u]+=siz[v];
31         f[u]=max(f[u],siz[v]);
32     }
33     f[u]=max(total-siz[u],f[u]);
34     if (f[u]<f[id]) id=u;
35 }
36 void get_dis(int u,int fa)
37 {
38     num[dis[u]%3]++;
39     for (int i=head[u];i!=-1;i=next[i])
40     {
41         int v=rea[i],fee=val[i];
42         if (v==fa||vis[v]) continue;
43         dis[v]=(dis[u]+fee)%3;
44         get_dis(v,u);
45     }
46 }
47 int calc(int u,int now)
48 {
49     num[0]=num[1]=num[2]=0;
50     dis[u]=now;get_dis(u,-1);
51     return num[1]*num[2]*2+num[0]*num[0];
52 }
53 void solve(int u)
54 {
55     ans+=calc(u,0);
56     vis[u]=1;
57     for (int i=head[u];i!=-1;i=next[i])
58     {
59         int v=rea[i],fee=val[i];
60         if (vis[v]) continue;
61         ans-=calc(v,fee);
62         total=siz[v];
63         id=0;
64         get_heart(v,-1);
65         solve(id);
66     }
67 }
68 int gcd(int a,int b)
69 {
70     return b?gcd(b,a%b):a;
71 }
72 int main()
73 {
74     scanf("%d",&n);
75     ans=cnt=id=0;
76     memset(vis,0,sizeof(vis));
77     memset(head,-1,sizeof(head));
78     for (int i=1,x,y,z;i<n;i++)
79     {
80         scanf("%d%d%d",&x,&y,&z);
81         add(x,y,z),add(y,x,z);
82     }
83     total=n,f[0]=inf;
84     get_heart(1,-1);
85     solve(id);
86     int ys=gcd(ans,n*n);
87     printf("%d/%d",ans/ys,n*n/ys);
88 }

 

posted @ 2017-11-01 15:02  Kaiser-  阅读(158)  评论(0编辑  收藏  举报