[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。

就当成点分治膜版题贴在这里吧
总有一天要跪着把树形dp的代码也贴上去的
点分治代码:
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<vector>
  5 using namespace std;
  6 
  7 inline int read(){
  8     char ch;
  9     int re=0;
 10     bool flag=0;
 11     while((ch=getchar())!='-'&&(ch<'0'||ch>'9'));
 12     ch=='-'?flag=1:re=ch-'0';
 13     while((ch=getchar())>='0'&&ch<='9')  re=re*10+ch-'0';
 14     return flag?-re:re;
 15 }
 16 
 17 struct edge{
 18     int to,w;
 19     edge(int to=0,int w=0):
 20         to(to),w(w){};
 21 };
 22 
 23 const int maxn=20001;
 24 vector<edge> G[maxn];
 25 int n;
 26 int root;
 27 int son[maxn],F[maxn];
 28 bool vis[maxn];
 29 int sum;
 30 int t[3];
 31 int d[maxn];
 32 int ans=0;
 33 
 34 inline void add_edge(int from,int to,int w){
 35     w%=3;
 36     G[from].push_back(edge(to,w));
 37     G[to].push_back(edge(from,w));
 38 }
 39 
 40 void init(){
 41     n=read();
 42     for(int i=0;i<n-1;i++){
 43         int from=read(),to=read(),w=read();
 44         add_edge(from,to,w);
 45     }
 46 }
 47 
 48 void getroot(int x,int fa){
 49     son[x]=1;
 50     F[x]=0;
 51     int dd=G[x].size();
 52     for(int i=0;i<dd;i++){
 53         edge &e=G[x][i];
 54         if(e.to!=fa&&!vis[e.to]){
 55             getroot(e.to,x);
 56             son[x]+=son[e.to];
 57             F[x]=max(F[x],son[e.to]);
 58         }
 59     }
 60     F[x]=max(F[x],sum-son[x]);
 61     if(F[x]<F[root])  root=x;
 62 }
 63 
 64 void get(int x,int fa){
 65     t[d[x]]++;
 66     int dd=G[x].size();
 67     for(int i=0;i<dd;i++){
 68         edge &e=G[x][i];
 69         if(!vis[e.to]&&e.to!=fa){
 70             d[e.to]=(d[x]+e.w)%3;
 71             get(e.to,x);
 72         }
 73     }
 74 }
 75 
 76 int calc(int x,int now){
 77     t[0]=t[1]=t[2]=0;
 78     d[x]=now;
 79     get(x,0);
 80     return t[1]*t[2]*2+t[0]*t[0];
 81 }
 82 
 83 void solve(int x){
 84     ans+=calc(x,0);
 85     vis[x]=1;
 86     int dd=G[x].size();
 87     for(int i=0;i<dd;i++){
 88         edge &e=G[x][i];
 89         if(!vis[e.to]){
 90             ans-=calc(e.to,e.w);
 91             root=0;
 92             sum=son[e.to];
 93             getroot(e.to,0);
 94             solve(root);
 95         }
 96     }
 97 }
 98 
 99 int gcd(int a,int b){
100     return b==0?a:gcd(b,a%b);
101 }
102 
103 int main(){
104     //freopen("temp.in","r",stdin);
105     init();
106     sum=F[root=0]=n;
107     memset(vis,0,sizeof vis);
108     getroot(1,0);
109     solve(root);
110     int t=gcd(ans,n*n);
111     printf("%d/%d\n",ans/t,n*n/t);
112     return 0;
113 }

我的理想把我丢在这个拥挤的人潮  车窗外已经是一片白雪茫茫
posted @ 2017-05-16 17:40  ZYBGMZL  阅读(211)  评论(0编辑  收藏  举报