点分治

Posted Milky Way

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了点分治相关的知识,希望对你有一定的参考价值。

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 }
View Code

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 }
View Code

 

以上是关于点分治的主要内容,如果未能解决你的问题,请参考以下文章

基于点分治的树分治

POJ 1741 Tree ——点分治

bzoj2599 [ IOI2011] -- 点分治

算法有关点分治的一些理解与看法

POJ 3714 分治/求平面最近点对

分治——最近点对