(题面来自Luogu)

题目描述

聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃、两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已经玩儿腻了这种低智商的游戏。

他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画n个“点”,并用n-1条“边”把这n个“点”恰好连通(其实这就是一棵树)。并且每条“边”上都有一个数。接下来由聪聪和可可分别随即选一个点(当然他们选点时是看不到这棵树的),如果两个点之间所有边上数的和加起来恰好是3的倍数,则判聪聪赢,否则可可赢。

聪聪非常爱思考问题,在每次游戏后都会仔细研究这棵树,希望知道对于这张图自己的获胜概率是多少。现请你帮忙求出这个值以验证聪聪的答案是否正确。

输入输出格式

输入格式:

输入的第1行包含1个正整数n。后面n-1行,每行3个整数x、y、w,表示x号点和y号点之间有一条边,上面的数是w。

输出格式:

以即约分数形式输出这个概率(即“a/b”的形式,其中a和b必须互质。如果概率为1,输出“1/1”)。

  用点分治统计从每个点u出发的路径,在cnt[k]中计数;其中k属于{0, 1, 2},表示该数组统计通过当前节点的长度%3等于k的路径数目。考虑将这些节点两两组合成长度%3等于0的路径:cnt[1]可以与cnt[2]两两组合,且题中给定的是有序点对,那么通过点u的满足条件的路径数ret += (cnt[2] * cnt[1] * 2)。cnt[0]可以两两组合,且可以重复,则ret += cnt[0] * cnt[0]。

代码:

 
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <cctype>
  5. #define BUG puts("$$$")
  6. #define maxn 20010
  7. using namespace std;
  8. const int inf = 0x3f3f3f3f;
  9. int n;
  10. template <typename T>
  11. void read(T &x) {
  12. x = 0;
  13. char ch = getchar();
  14. int f = 1;
  15. while (!isdigit(ch)) {
  16. if (ch == '-') f = -1;
  17. ch = getchar();
  18. }
  19. while (isdigit(ch)) {
  20. x = x * 10 + (ch ^ 48);
  21. ch = getchar();
  22. }
  23. x *= f;
  24. }
  25. long long gcd(long long a, long long b) {
  26. if (!b) return a;
  27. return gcd(b, a % b);
  28. }
  29. int head[maxn], top;
  30. struct E {
  31. int to, nxt, w;
  32. } edge[maxn << 1];
  33. inline void insert(int u, int v, int w) {
  34. edge[++top] = (E) {v, head[u], w};
  35. head[u] = top;
  36. }
  37. int cnt[3];
  38. int size[maxn], Size, mn, root;
  39. bool vis[maxn];
  40. void find_rt(int u, int pre) {
  41. size[u] = 1;
  42. int son = 0;
  43. for (int i = head[u]; i; i = edge[i].nxt) {
  44. int v = edge[i].to;
  45. if (v == pre || vis[v]) continue;
  46. find_rt(v, u);
  47. size[u] += size[v];
  48. if (size[v] > size[son]) son = v;
  49. }
  50. int cur = max(size[son], Size - size[u]);
  51. if (cur < mn)
  52. mn = cur, root = u;
  53. }
  54. void dfs(int u, int pre, int depth, int val) {
  55. cnt[depth % 3] += val;
  56. for (int i = head[u]; i; i = edge[i].nxt) {
  57. int v = edge[i].to;
  58. if (v == pre || vis[v]) continue;
  59. dfs(v, u, depth + edge[i].w, val);
  60. }
  61. }
  62. long long solve(int u, int extra) {
  63. dfs(u, 0, extra, 1);
  64. long long ret = 1LL * cnt[1] * cnt[2] * 2 + 1LL * cnt[0] * cnt[0];
  65. dfs(u, 0, extra, -1);
  66. return ret;
  67. }
  68. long long ans;
  69. void divide(int u) {
  70. vis[u] = true;
  71. ans += solve(u, 0);
  72. int curSize = Size;
  73. for (int i = head[u]; i; i = edge[i].nxt) {
  74. int v = edge[i].to;
  75. if (vis[v]) continue;
  76. ans -= solve(v, edge[i].w);
  77. mn = inf, Size = size[u] > size[v] ? size[v] : curSize - size[u];
  78. find_rt(v, u);
  79. divide(root);
  80. }
  81. }
  82. int main() {
  83. read(n);
  84. int u, v, w;
  85. for (int i = 1; i < n; ++i) {
  86. read(u), read(v), read(w);
  87. insert(u, v, w), insert(v, u, w);
  88. }
  89. mn = inf, Size = n;
  90. find_rt(1, 0);
  91. divide(root);
  92. long long down = 1LL * n * n, k = gcd(down, ans);
  93. printf("%lld/%lld", ans / k, down / k);
  94. return 0;
  95. }

【P2634】聪聪可可——点分治的更多相关文章

  1. [bzoj2152][聪聪和可可] (点分治+概率)

    Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好 ...

  2. bzoj2152 / P2634 [国家集训队]聪聪可可(点分治)

    P2634 [国家集训队]聪聪可可 淀粉质点分治板子 边权直接 mod 3 直接点分治统计出所有的符合条件的点对再和总方案数约分 至于约分.....gcd搞搞就好辣 #include<iostr ...

  3. 洛谷 P2634 [国家集训队]聪聪可可-树分治(点分治,容斥版) +读入挂+手动O2优化吸点氧才过。。。-树上路径为3的倍数的路径数量

    P2634 [国家集训队]聪聪可可 题目描述 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一 ...

  4. P2634 [国家集训队]聪聪可可(题解)(点分治)

    P2634 [国家集训队]聪聪可可(题解)(点分治) 洛谷题目 #include<iostream> #include<cstdlib> #include<cstdio& ...

  5. 模板—点分治A(容斥)(洛谷P2634 [国家集训队]聪聪可可)

    洛谷P2634 [国家集训队]聪聪可可 静态点分治 一开始还以为要把分治树建出来……• 树的结构不发生改变,点权边权都不变,那么我们利用刚刚的思路,有两种具体的分治方法.• A:朴素做法,直接找重心, ...

  6. AC日记——【模板】点分治(聪聪可可) 洛谷 P2634

    [模板]点分治(聪聪可可) 思路: 点分治: (感谢灯神) 代码: #include <bits/stdc++.h> using namespace std; #define maxn 2 ...

  7. 洛谷-P2634 [国家集训队]聪聪可可 点分治

    Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好 ...

  8. 洛谷P2634 [国家集训队]聪聪可可 (点分治)

    题目描述 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已 ...

  9. 洛谷 P2634 BZOJ 2152 【模板】点分治(聪聪可可)

    题目描述 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已 ...

随机推荐

  1. mysql 事务的日志

    事务的日志 1.redo log redo:"重做",记录的是,内存数据页的变化过程 1)作用 在事务ACID过程中,实现的是 "D" 持久化的作用. 2)工作 ...

  2. ASP.NET Core Authentication系列(二)实现认证、登录和注销

    前言 在上一篇文章介绍ASP.NET Core Authentication的三个重要概念,分别是Claim, ClaimsIdentity, ClaimsPrincipal,以及claims-bas ...

  3. 阅读源码,通过LinkedList回顾基础

    目录 前言 类签名 泛型 Serializable和Cloneable Deque List和AbstractList RandomAccess接口(没实现) 变量 构造函数 常用方法 List体系下 ...

  4. 从ReentrantLock加锁解锁角度分析AQS

    本文用于记录在学习AQS时,以ReentrantLock为切入点,深入源码分析ReentrantLock的加锁和解锁过程. 同步器AQS的主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理 ...

  5. 你说一下对Java中的volatile的理解吧

    前言 volatile相关的知识其实自己一直都是有掌握的,能大概讲出一些知识,例如:它可以保证可见性:禁止指令重排.这两个特性张口就来,但要再往深了问,具体是如何实现这两个特性的,以及在什么场景下使用 ...

  6. How to using code find the menu label of Menus【X++】

    // VAR Changed by Xie Yu Fan.Fandy 谢宇帆 static void XIE_FindMenu(Args _args) { Dialog dlg = new Dialo ...

  7. C/C++四种取整函数floor,ceil,trunc,round

    处理浮点数操作常用到取整函数,C/C++提供了四种取整函数 floor函数 floor函数:向下取整函数,或称为向负无穷取整 double floor(double x); floor(-5.5) = ...

  8. Spring Security 实战干货:OAuth2授权请求是如何构建并执行的

    在Spring Security 实战干货:客户端OAuth2授权请求的入口中我们找到了拦截OAuth2授权请求入口/oauth2/authorization的过滤器OAuth2Authorizati ...

  9. C语言利用结构体数组实现学生成绩管理系统

    这篇文章主要为大家详细介绍了C语言利用结构体数组实现学生成绩管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 要求: 某班有最多不超过30人(具体人数由键盘输入) ...

  10. Pytest系列(八) - 自定义标记mark的使用

    一.前言: pytest 支持自定义标记,自定义标记方便用例模块划分,也可以理解方便管理,配合标记参数 -m使用 二.示例代码 # -*- coding: utf-8 -*- # @Time : 20 ...