【BZOJ2152】聪聪可可(点分治)
2017-12-09 08:35
417 查看
题面
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
51 2 1
1 3 2
1 4 1
2 5 3
Sample Output
13/25Hint
样例说明: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)。
数据规模和约定
对于30%的数据,n≤1000 另有20%的数据,给出的树中每个节点的度不超过2;
对于100%的数据,n≤20000
题解
还是点分治因为求点对的距离关于3的膜
因此只要统计子树中的距离膜3的点个数即可
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define MAX 30000 inline int read() { int x=0,t=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } struct Line { int v,next,w; }e[MAX<<1]; int h[MAX],cnt=1; int size[MAX],Size,minr,root; int S[3],tot,num[3]; bool vis[MAX]; int n; inline void Add(int u,int v,int w) { e[cnt]=(Line){v,h[u],w}; h[u]=cnt++; } void Getroot(int u,int ff) { size[u]=1; int ret=0; for(int i=h[u];i;i=e[i].next) { int v=e[i].v; if(v==ff||vis[v])continue; Getroot(v,u); size[u]+=size[v]; ret=max(ret,size[v]); } ret=max(ret,Size-size[u]); if(ret<minr)minr=ret,root=u; } void Getdep(int u,int ff,int dd) { S[dd%3]++; for(int i=h[u];i;i=e[i].next) { int v=e[i].v; if(v==ff||vis[v])continue; Getdep(v,u,(dd+e[i].w)%3); } } void Calc(int u,int fl,int pr) { memset(S,0,sizeof(S)); Getdep(u,u,0); if(fl) { num[0]+=2*S[1]*S[2]+S[0]*S[0]; num[1]+=2*S[0]*S[1]+S[2]*S[2]; num[2]+=2*S[0]*S[2]+S[1]*S[1]; } else { pr%=3; num[(0+pr)%3]-=2*S[1]*S[2]+S[0]*S[0]; num[(1+pr)%3]-=2*S[0]*S[1]+S[2]*S[2]; num[(2+pr)%3]-=2*S[0]*S[2]+S[1]*S[1]; } } void DFS(int u) { Calc(u,1,0); vis[u]=true; for(int i=h[u];i;i=e[i].next) { int v=e[i].v; if(vis[v])continue; Calc(v,0,e[i].w*2); minr=n;Size=size[v]; Getroot(v,u); DFS(root); } } int gcd(int a,int b) { return !a?b:gcd(b%a,a); } int main() { Size=n=read(); for(int i=1,u,v,w;i<n;++i) { u=read(),v=read(),w=read(); Add(u,v,w);Add(v,u,w); } minr=n;Getroot(1,1); DFS(root); int tt=num[0]+num[1]+num[2]; int dd=gcd(tt,num[0]); printf("%d/%d\n",num[0]/dd,tt/dd); return 0; }
相关文章推荐
- BZOJ 2152 聪聪可可 [树分治 or 树形DP]
- bzoj2152 聪聪可可 点分治
- [bzoj2152]:聪聪可可(点分治)[洛谷P2634]
- bzoj 2152 聪聪可可(点分治)
- [bzoj2152]聪聪可可——点分治
- 【bzoj2152】聪聪可可 树的点分治
- 【树分治】BZOJ2152 聪聪可可
- [bzoj] 2152 聪聪可可 || 树分治
- bzoj 2152:聪聪可可(点分治)
- 【bzoj2152】【聪聪可可】【点分治】
- 【BZOJ】2152 聪聪可可 点分治
- bzoj 2152: 聪聪可可(点分治)
- bzoj2152 聪聪可可 点分治
- bzoj2152: 聪聪可可(点分治)
- BZOJ2152[聪聪可可] 点分治
- BZOJ2152 聪聪可可 点分治
- BZOJ 2152: 聪聪可可 点分治/树dp
- bzoj 2152: 聪聪可可 点分治
- [国家集训队][bzoj 2152] 聪聪可可 [点分治]
- BZOJ2152: 聪聪可可 【点分治】