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