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。


思路:
树上统计路径问题,对于20000个点,点分治算法足以解决。

Code:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define INF 0x3f3f3f3f
 4 #define M(a, b) memset(a, b, sizeof(a))
 5 const int maxn = 20000 + 5;
 6 int sum, ans, n, root, d[maxn], mod[3], son[maxn], f[maxn];
 7 bool vis[maxn];
 8 struct Node {
 9     int to, w;
10 };
11 vector<Node> G[maxn*2];
12 
13 int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}
14 
15 void getroot(int x, int fa) {
16     f[x] = 0, son[x] = 1;
17     for (int i = 0; i < G[x].size(); ++i) {
18         int v = G[x][i].to;
19         if (vis[v] || v == fa) continue;
20         getroot(v, x);
21         son[x] += son[v];
22         f[x] = max(f[x], son[v]);
23     }
24     f[x] = max(f[x], sum-son[x]);
25     if (f[x] < f[root]) root = x;
26 }
27 
28 void getdeep(int x, int fa) {
29     mod[d[x]]++;
30     for (int i = 0; i < G[x].size(); ++i) {
31         int v = G[x][i].to;
32         if (vis[v] || v == fa) continue;
33         d[v] = (d[x] + G[x][i].w) % 3;
34         getdeep(v, x);
35     }
36 }
37 
38 int cal(int x, int now) {
39     d[x] = now;
40     mod[0] = mod[1] = mod[2] = 0;
41     getdeep(x, 0);
42     return mod[1]*mod[2]*2 + mod[0]*mod[0];
43 }
44 
45 void work(int x) {
46     ans += cal(x, 0);
47     vis[x] = 1;
48     for (int i = 0; i < G[x].size(); ++i) {
49         int v = G[x][i].to;
50         if (vis[v]) continue;
51         ans -= cal(v, G[x][i].w);
52         sum = son[v];
53         root = 0;
54         getroot(v, 0);
55         work(root);
56     }
57 }
58 
59 int main() {
60     ios::sync_with_stdio(false);
61     while(cin >> n) {
62         int a, b, c;
63         memset(vis, 0, sizeof(vis));
64         for (int i = 1; i <= n; ++i) G[i].clear();
65         for (int i = 1; i < n; ++i) {
66             cin >> a >> b >> c; c %= 3;
67             G[a].push_back(Node{b, c});
68             G[b].push_back(Node{a, c});
69         }
70         sum = n;
71         ans = 0;
72         root = 0;
73         f[root] = INF;
74         getroot(1, 0);
75         work(root);
76         int all = n * n;
77         int e = gcd(all, ans);
78         cout << ans/e << "/" << all/e << endl;
79     }
80 
81     return 0;
82 }

 

posted @ 2017-03-12 17:18  Robin!  阅读(121)  评论(0编辑  收藏  举报