差分约束系统:
正向建 (B-Age C) 为 (A ightarrow B) 权 (C),求最长路。
或反向建 (B-Age C) 为 (B ightarrow B) 权 (-C),求最短路。
均只能用 SPFA 做。注意判环!
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
int n, K, d[300005], enq[300005];
int head[300005], nex[300005], to[300005], w[300005];
bool inq[300005];
long long ans;
queue<int> q;
inline void add(const int& x, const int& y, const int& z) {
nex[++head[0]]=head[x], head[x]=head[0], to[head[0]]=y, w[head[0]]=z;
}
inline bool spfa() {
q.push(n+1), inq[n+1]=true, enq[n+1]=1;
while (!q.empty()) {
register int now=q.front(); q.pop(); inq[now]=false;
for (register int i=head[now]; i; i=nex[i]) if (d[now]+w[i] > d[to[i]]) {
d[to[i]]=d[now]+w[i];
if (!inq[to[i]]) {q.push(to[i]), inq[to[i]]=true; if (++enq[to[i]]>=n) return true; }
}
}
return false;
}
int main() {
scanf("%d%d", &n, &K);
while (K--) {
register int X, A, B;
scanf("%d%d%d", &X, &A, &B);
if (X==1) add(A, B, 0), add(B, A, 0); // A = B
if (X==2) add(A, B, 1); // B > A
if (X==3) add(B, A, 0); // A ≥ B
if (X==4) add(B, A, 1); // A > B
if (X==5) add(A, B, 0); // B ≥ A
if (!(X&1) && (A==B)) {puts("-1
"); return 0; } // A ≠ A
}
for (int i=n; i; --i) add(n+1, i, 1);
if (spfa()) {puts("-1
"); return 0; }
for (int i=1; i<=n; ++i) ans+=d[i];
printf("%lld
", ans);
return 0;
}