[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。
就当成点分治膜版题贴在这里吧
总有一天要跪着把树形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 }
我的理想把我丢在这个拥挤的人潮 车窗外已经是一片白雪茫茫