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
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。
【样例说明】
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 }