我感觉差分约束比较好想。
1.把相同的合并成一个点
2.如果是小于就建一条长度为1的边,不然就建一条长度为0的边
3.跑最长路,判断是否有环,没有就输出
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int N = 1e5 + 10;
int n, m, X[N], Y[N]; bool Z[N];
int tot, Head[N], Edge[N], Next[N], Leng[N];
int fa[N], d[N], c[N]; bool v[N];
void add(int x, int y, int z) {
tot++;
Edge[tot] = y;
Leng[tot] = z;
Next[tot] = Head[x];
Head[x] = tot;
}
int findfa(int x) {
return x == fa[x] ? x : fa[x] = findfa(fa[x]);
}
void SPFA() {
queue<int> q; m = 0;
for (int i = 1; i <= n; i++)
if (fa[i] == i) {
++m;
d[i] = 1;
v[i] = 1;
q.push(i);
}
while (q.size()) {
int x = q.front(); q.pop(); v[x] = 0;
for (int i = Head[x]; i; i = Next[i]) {
int y = Edge[i];
if (d[y] < d[x] + Leng[i]) {
d[y] = d[x] + Leng[i];
if ((++c[y]) > m) { puts("-1"); return; }
if (!v[y]) q.push(y), v[y] = 1;
}
}
}
long long ans = 0;
for (int i = 1; i <= n; i++)
ans += 1ll * d[findfa(i)];
cout << ans << endl;
}
int main() {
int t; cin >> n >> t;
for (int i = 1; i <= n; i++) fa[i] = i;
for (int i = 1; i <= t; i++) {
int x, y, z; scanf("%d%d%d", &z, &x, &y);
if (z == 1) fa[findfa(x)] = findfa(y);
else {
++m;
if (z == 3 || z == 4) swap(x, y);
if (z == 2 || z == 4) Z[m] = 1;
X[m] = x, Y[m] = y;
}
}
for (int i = 1; i <= m; i++) {
int fx = findfa(X[i]);
int fy = findfa(Y[i]);
if (fx == fy && Z[i]) { puts("-1"); return 0; }
add(fx, fy, Z[i]);
}
SPFA(); return 0;
}