【bzoj2152】聪聪可可 点分治
2015-12-29 09:11
337 查看
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。
HINT
Source
树的分治树分治。
每个点到根节点的距离模三,统计模三为0,1,2的个数。
然后每次计算u的一个新的子树时,记新的模0,1,2的个数分别为zero,one,two。对答案的贡献是:
zero∗d[u][0]+one∗d[u][2]+two∗d[u][1]
其实跟NOIP2014联合权值那个题有点像。传送门:NOIP2014联合权值
最后别忘了乘二,还有加上起点终点是同一点。
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int SZ = 2000010; const int INF = 1000000010; int head[SZ],nxt[SZ],tot = 0,n; struct edge{ int t,d; }l[SZ]; void build(int f,int t,int d) { l[++ tot].t = t; l[tot].d = d; nxt[tot] = head[f]; head[f] = tot; } int root,maxn = INF; bool rt[SZ]; int find(int u,int fa,int n) { int sz = 1; int now = 0; for(int i = head[u];i;i = nxt[i]) { int v = l[i].t; if(v != fa && !rt[v]) { int son = find(v,u,n); sz += son; now = max(now,son); } } now = max(now,n - sz); if(maxn > now) maxn = now,root = u; return sz; } int ans = 0; int dist[SZ][3]; void dfsdist(int u,int fa,int d,int &zero,int &one,int &two) { if(d % 3 == 0) zero ++; else if(d % 3 == 1) one ++; else two ++; for(int i = head[u];i;i = nxt[i]) { int v = l[i].t; if(!rt[v] && v != fa) dfsdist(v,u,d + l[i].d,zero,one,two); } } int dfssz(int u,int fa) { int sz = 1; for(int i = head[u];i;i = nxt[i]) { int v = l[i].t; if(v != fa && !rt[v]) sz += dfssz(v,u); } return sz; } void dfs(int x,int fa) { int sz = dfssz(x,fa); maxn = n; find(x,fa,sz); int u = root; rt[u] = 1; dist[u][0] = 1; for(int i = head[u];i;i = nxt[i]) { int v = l[i].t; int zero = 0,one = 0,two = 0; if(!rt[v]) { dfsdist(v,u,l[i].d,zero,one,two); ans += zero * dist[u][0] + one * dist[u][2] + two * dist[u][1]; dist[u][0] += zero; dist[u][1] += one; dist[u][2] += two; dfs(v,u); } } } int gcd(int a,int b) { return b == 0 ? a : gcd(b,a % b); } void scanf(int &n) { n = 0; char a = getchar(); bool flag = 0; while(a < '0' || a > '9') { if(a == '-') flag = 1; a = getchar(); } while(a >= '0' && a <= '9') n = (n << 3) + (n << 1) + a - '0',a = getchar(); if(flag) n = -n; } int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); scanf(n); for(int i = 1;i < n;i ++) { int a,b,c; scanf(a),scanf(b),scanf(c); build(a,b,c); build(b,a,c); } dfs(1,0); ans = ans * 2 + n; int d = gcd(ans,n * n); // for(int i = 1;i <= n;i ++) printf("%d %d %d\n",dist[i][0],dist[i][1],dist[i][2]); printf("%d/%d",ans/d,n*n/d); return 0; }
相关文章推荐
- js中i++与++i的区别
- QThread中的事件循环
- 适配iOS9
- 将sql文件导入数据库(50M以上文件的导入)
- 使用 BASH 作为 CGI 进行 HTTP 文件上传
- Xcode-程序开发设计-01UIKit 框架
- 编译安装httpd-2.2.29.tar详解
- BTS PenTesting Lab - A10 Unvalidated Redirect & Forward..
- 【深入ASP.NET原理系列】--ASP.NET请求管道、应用程序生命周期、整体运行机制
- android Graphics( 五):drawText()详解
- shell脚本中的数学运算
- 九度OJ 1065 输出梯形 (模拟)
- Eclipse构建Maven项目
- IOS开发 @property中assign、copy 、retain等关键字的理解
- iOS Quartz 2D 绘制图形(线段\三角形\矩形\圆\圆弧等)
- 2015.12.27和2015.12.28回顾
- js实现商城星星评分的效果
- LeetCode 062 Unique Paths
- 16-《电子入门趣谈》第三章_电子世界中的五官---传感器-3.2.1DS18B20
- linux 常用命令