聪聪可可【国家集训队】

 题目链接:https://www.luogu.org/problemnew/show/P2634

 

  题意:

  给你一棵树,问任选两个点(x,y)满足x到y的树上距离是3的倍数的概率。

  题解:

  只要求出一共有多少个点对(x,y)满足x到y的树上距离为3的倍数即可。

  那么怎么求呢?点分治。

  什么是点分治呢?

  就是先找到树的重心(就是以它为根时最大子树大小最小的节点),把它定为根,然后求经过根的路径条数有多少。再递归求每个子树节点即可。复杂度O(n*logn)。

  为什么要用点分治呢?

  因为点分治可以保证最坏复杂度为O(n*logn)。具体证明有兴趣的同学可以百度一下。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define LL long long
 5 #define RI register int
 6 using namespace std;
 7 const int INF = 0x7ffffff ;
 8 const int N = 20000 + 10 ;
 9 
10 inline int read() {
11     int k = 0 , f = 1 ; char c = getchar() ;
12     for( ; !isdigit(c) ; c = getchar())
13       if(c == '-') f = -1 ;
14     for( ; isdigit(c) ; c = getchar())
15       k = k*10 + c-'0' ;
16     return k*f ;
17 }
18 struct Edge {
19     int to, next, val ;
20 }e[N<<1] ;
21 int n, root, ans = 0, sum ; int head[N], siz[N], dep[N], t[5], f[N] ;
22 bool vis[N] ;
23 inline void add_edge(int x,int y,int z) {
24     static int cnt = 0 ;
25     e[++cnt].to = y, e[cnt].val = z, e[cnt].next = head[x], head[x] = cnt ;
26 }
27 
28 void get_deep(int x,int fa) {
29     t[dep[x]] ++ ;
30     for(int i=head[x];i;i=e[i].next) {
31         int y = e[i].to ;
32         if(y == fa || vis[y]) continue ;
33         dep[y] = (dep[x] + e[i].val)%3 ;
34         get_deep(y,x) ;
35     }
36 }
37 inline int calc(int x,int deep) {
38     t[0] = t[1] = t[2] = 0 ;
39     dep[x] = deep ;
40     get_deep(x,0) ;
41     return t[1]*t[2]*2 + t[0]*t[0] ;
42 }
43 void get_root(int x,int fa) {
44     siz[x] = 1 ; f[x] = 0 ;
45     for(int i=head[x];i;i=e[i].next) {
46         int y = e[i].to ;
47         if(y == fa || vis[y]) continue ;
48         get_root(y,x) ; siz[x] += siz[y] ;
49         f[x] = max(f[x],siz[y]) ;
50     }
51     f[x] = max(f[x],sum-siz[x]) ;
52     if(f[x] < f[root]) root = x ;
53 }
54 void solve(int x) {
55     ans += calc(x,0) ;
56     vis[x] = 1 ;
57     for(int i=head[x];i;i=e[i].next) {
58         int y = e[i].to ;
59         if(vis[y]) continue ;
60         ans -= calc(y,e[i].val) ; // 
61         root = 0 ; sum = siz[y] ; 
62         get_root(y,0) ;
63         solve(root) ;
64     }
65 }
66 
67 int gcd(int a,int b) { return b == 0 ? a : gcd(b,a%b) ; }
68 int main() {
69     n = read() ;
70     int x, y, z ;
71     for(int i=1;i<n;i++) {
72         x = read(), y = read(), z = read()%3 ;
73         add_edge(x,y,z) ; add_edge(y,x,z) ;
74     }
75     sum = f[0] = n ; root = 0 ;
76     get_root(1,0) ;
77     solve(root) ;
78     int fm = n*n ;
79     int gg = gcd(fm,ans) ; 
80     printf("%d/%d",ans/gg,fm/gg) ;
81     return 0 ;
82 }
View Code

 ——end ;

原文地址:https://www.cnblogs.com/zub23333/p/8574209.html