P8710. 网络分析

考点

  • 并查集

题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <bits/stdc++.h>
using namespace std;
const int LEN = 1e5 + 50;
int n, m, fa[LEN], val[LEN], add[LEN];

int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}

void join(int x, int y) {
int a = find(x), b = find(y);
//剪枝,否则超时
if (a == b) return;
for (int i = 1; i <= n; ++i) {
val[i] += add[find(i)];
}
memset(add, 0, sizeof(add));
fa[a] = b;
}

int main() {
cin >> n >> m;
int opt, a, b, p, t;
for (int i = 1; i <= n; ++i) fa[i] = i;
while (m--) {
cin >> opt;
if (opt == 1) {
cin >> a >> b;
join(a, b);
} else if (opt == 2) {
cin >> p >> t;
add[find(p)] += t;
}
}
for (int i = 1; i <= n; ++i) cout << val[i] + add[find(i)] << " ";
return 0;
}

思路

将并查集作为数据结构的好题很少见啊~

更新并查集的一个子结点,如何将影响扩散至整个集合?

将各个子结点的累加量,记录在该子结点的祖先,即add[祖先]保存

每次合并前,遍历整个集合,把祖先记录的累加量一次性赋给其所在集合内的所有子结点

假设集合A有累加量4,B有累加量8,A、B两集合即将合并

我们应分别将4赋给集合A的所有结点,8赋给集合B的所有结点后,两集合再合并

否则强行合并的话,最终就变成了B集合有累加量4 + 8 = 12,这是不对的