bzoj 1468 Tree
题意:给出一棵树,每条边有一个权值,求有多少两点间路径和小于 k
思路:点分治入门题
1 #include <cstdio> 2 #include <string> 3 #include <vector> 4 #include <algorithm> 5 6 const int N = 40005, INF = 0x3f3f3f3f; 7 8 int read() { 9 int x = 0, f = 1; 10 char c = getchar(); 11 while (!isdigit(c)) { 12 if (c == ‘-‘) f = -1; 13 c = getchar(); 14 } 15 while (isdigit(c)) { 16 x = (x << 3) + (x << 1) + (c ^ 48); 17 c = getchar(); 18 } 19 return x * f; 20 } 21 22 int max(int x, int y) { if (x >= y) return x; return y; } 23 24 struct Edge { int to, cost; }; 25 std::vector<Edge> edges; 26 std::vector<int> G[N]; 27 int n, k, sum, root, ans; 28 int size[N], son[N], deep[N], d[N], vis[N]; 29 30 void addEdge(int from, int to, int cost) { 31 G[from].push_back(edges.size()); 32 edges.push_back((Edge){to, cost}); 33 } 34 35 void getRoot(int cur, int father) { 36 size[cur] = 1, son[cur] = 0; 37 int sz = G[cur].size(); 38 for (int i = 0; i < sz; ++ i) { 39 Edge e = edges[G[cur][i]]; 40 if (!vis[e.to] && e.to != father) { 41 getRoot(e.to, cur); 42 size[cur] += size[e.to]; 43 son[cur] = max(son[cur], size[e.to]); 44 } 45 } 46 son[cur] = max(son[cur], sum - size[cur]); 47 if (son[cur] < son[root]) root = cur; 48 } 49 50 void getDeep(int cur, int father) { 51 deep[++deep[0]] = d[cur]; 52 int sz = G[cur].size(); 53 for (int i = 0; i < sz; ++ i) { 54 Edge e = edges[G[cur][i]]; 55 if (!vis[e.to] && e.to != father) { 56 d[e.to] = d[cur] + e.cost; 57 getDeep(e.to, cur); 58 } 59 } 60 } 61 62 int cal(int cur, int cost) { 63 d[cur] = cost, deep[0] = 0; 64 getDeep(cur, 0); 65 std::sort(deep + 1, deep + deep[0] + 1); 66 int l = 1, r = deep[0], res = 0; 67 while (l < r) { 68 if (deep[l] + deep[r] <= k) res += r-l, ++l; 69 else --r; 70 } 71 return res; 72 } 73 74 void solve(int cur) { 75 ans += cal(cur, 0), vis[cur] = 1; 76 int sz = G[cur].size(); 77 for (int i = 0; i < sz; ++ i) { 78 Edge e = edges[G[cur][i]]; 79 if (!vis[e.to]) { 80 ans -= cal(e.to, e.cost); 81 sum = size[e.to], root = 0; 82 getRoot(e.to, 0), solve(root); 83 } 84 } 85 } 86 87 int main() { 88 n = read(); 89 for (int i = 1; i < n; ++ i) { 90 int u = read(), v = read(), c = read(); 91 addEdge(u, v, c), addEdge(v, u, c); 92 } 93 k = read(); 94 root = 0, son[0] = sum = n; 95 getRoot(1, 0), solve(root); 96 printf("%d\n", ans); 97 return 0; 98 }
bzoj 2152 聪聪可可
题意:给出一棵树,每条边有一个权值,求两点间路径和是 3 的倍数的概率
思路:点分治,一边加一边 %3,deep 数组大小为 3,分别表示不同的余数
1 #include <cstdio> 2 #include <string> 3 #include <vector> 4 5 const int N = 20005; 6 7 int read() { 8 int x = 0, f = 1; 9 char c = getchar(); 10 while (!isdigit(c)) { 11 if (c == ‘-‘) f = -1; 12 c = getchar(); 13 } 14 while (isdigit(c)) { 15 x = (x << 3) + (x << 1) + (c ^ 48); 16 c = getchar(); 17 } 18 return x * f; 19 } 20 21 int max(int x, int y) { if (x >= y) return x; return y; } 22 int gcd(int x, int y) { return y == 0 ? x : gcd(y, x % y); } 23 24 struct Edge { int to, cost; }; 25 std::vector<Edge> edges; 26 std::vector<int> G[N]; 27 28 int ans, sum, root, size[N], deep[3], d[N], son[N], vis[N]; 29 30 void addEdge(int from, int to, int cost) { 31 G[from].push_back(edges.size()); 32 edges.push_back((Edge){to, cost}); 33 } 34 35 void getRoot(int cur, int father) { 36 size[cur] = 1, son[cur] = 0; 37 int sz = G[cur].size(); 38 for (int i = 0; i < sz; ++ i) { 39 Edge e = edges[G[cur][i]]; 40 if (!vis[e.to] && e.to != father) { 41 getRoot(e.to, cur); 42 size[cur] += size[e.to]; 43 son[cur] = max(son[cur], size[e.to]); 44 } 45 } 46 son[cur] = max(son[cur], sum - size[cur]); 47 if (son[cur] < son[root]) root = cur; 48 } 49 50 void getDeep(int cur, int father) { 51 ++deep[d[cur] % 3]; 52 int sz = G[cur].size(); 53 for (int i = 0; i < sz; ++ i) { 54 Edge e = edges[G[cur][i]]; 55 if (!vis[e.to] && e.to != father) { 56 d[e.to] = d[cur] + e.cost; 57 getDeep(e.to, cur); 58 } 59 } 60 } 61 62 int cal(int cur, int cost) { 63 deep[0] = deep[1] = deep[2] = 0; 64 d[cur] = cost, getDeep(cur, 0); 65 return deep[0] * deep[0] + deep[1] * deep[2] * 2; 66 } 67 68 void solve(int cur) { 69 ans += cal(cur, 0), vis[cur] = 1; 70 int sz = G[cur].size(); 71 for (int i = 0; i < sz; ++ i) { 72 Edge e = edges[G[cur][i]]; 73 if (!vis[e.to]) { 74 ans -= cal(e.to, e.cost); 75 sum = size[e.to], root = 0; 76 getRoot(e.to, 0), solve(root); 77 } 78 } 79 } 80 81 int main() { 82 int n = read(); 83 for (int i = 1; i < n; ++ i) { 84 int u = read(), v = read(), c = read(); 85 addEdge(u, v, c), addEdge(v, u, c); 86 } 87 root = 0, son[0] = sum = n; 88 getRoot(1, 0), solve(root); 89 int t = gcd(ans, n * n); 90 printf("%d/%d\n", ans / t, n * n / t); 91 return 0; 92 }