简单读题后,我(蒟蒻)读出了这些信息:
1.不在一个连通块的查询直接输出nan
。
2.连通块中如果有正环或负环,那么在这个连通块的查询答案都是inf
。
3.如果不是以上两种情况,就输出他们一路上的边权。
所以我想到了DSU。
由于还要处理边权,所以自然而然的想到了带权DSU。
显然,环的出现源于同个DSU的连边。
但环可以分成两种:零环/非零环(需要处理成inf)。
零环显然对答案没影响,不需要考虑。
(如果画个图可能更清晰,但我较懒,所以听评讲吧)
非零环显然会将整个DSU中的查询变为inf,所以直接标记根节点,表示本DSU需要输出inf。
于是就100pts了。
除去调代码(可能是我码力太差了)比较久外,其他还是很好想的。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, m, q;
int p[200005];
int d[200005];
int find(int x) {
if (x == p[x])
return x;
else {
int t = p[x];
p[x] = find(p[x]);
d[x] += d[t];
return p[x];
}
}
int inf[200005];
signed main() {
scanf("%lld%lld%lld", &n, &m, &q);
for (int i = 1; i <= n; i++) p[i] = i, d[i] = 0;
for (int i = 1; i <= m; i++) {
int a, b, c;
scanf("%lld%lld%lld", &a, &b, &c);
int u = find(a);
int v = find(b);
if (u == v) {
if (c == d[a] - d[b])
continue;
else
inf[u] = 1;
} else if (u < v) {
p[u] = v;
d[u] = c + d[b] - d[a];
if (inf[u])
inf[v] = 1;
} else {
p[v] = u;
d[v] = -c + d[a] - d[b];
if (inf[v])
inf[u] = v;
}
}
for (int i = 1; i <= q; i++) {
int a, b;
scanf("%lld%lld", &a, &b);
int u = find(a), v = find(b);
if (u != v)
printf("nan\n");
else {
if (inf[u])
printf("inf\n");
else
printf("%lld\n", d[a] - d[b]);
}
}
return 0;
}
终于出现了一次D题能被我切掉的期末考了。