P2294. 狡猾的商人

考点

  • 边带权并查集

题解

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
39
40
41
42
43
44
#include <bits/stdc++.h>
using namespace std;
const int LEN = 1e5 + 50;
int n, m, fa[LEN], dis[LEN];

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

void join(int x, int y, int w) {
int a = find(x), b = find(y);
fa[a] = b;
dis[a] = dis[y] + w - dis[x];
}

void work() {
bool flag = true;
int x, y, w;
cin >> n >> m;
for (int i = 0; i <= n; ++i) fa[i] = i, dis[i] = 0;
while (m--) {
cin >> x >> y >> w;
--x;
if (find(x) != find(y)) {
join(x, y, w);
} else {
if (dis[x] - dis[y] != w) {
flag = false;
}
}
}
flag ? puts("true") : puts("false");
}

int main() {
int t;
cin >> t;
while (t--) work();
return 0;
}

思路

询问当前请求是否满足前提条件的,要量化之前的关系保存下来的,一般是边带权并查集

路径压缩

dis[x]x结点到当前祖先结点的步数,通过作图可知[x, y] = dis[x - 1] - dis[y]

通过编程实现就是

1
新dis[x] = 原dis[x] + 新dis[x的父亲]

合并

同样作图,很显然能得到

1
dis[a] = dis[y] + w - dis[x];