You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

86 lines
2.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100010, M = 300010;
stack<int> q; // 有时候换成栈判断环很快就能找到答案
LL dist[N];
bool st[N];
int cnt[N];
int n, m; // 表示点数和边数
// 邻接表
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
bool spfa() { // 最长路,判正环
memset(dist, -0x3f, sizeof dist); // 最长路,需要初始化为-0x3f
// 超级源点出发
dist[0] = 0;
q.push(0);
st[0] = 1;
while (q.size()) {
int u = q.top();
q.pop();
st[u] = 0;
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (dist[v] < dist[u] + w[i]) { // 求最长路
dist[v] = dist[u] + w[i];
cnt[v] = cnt[u] + 1;
// 注意多加了超级源点,共n+1个节点边数最多是n
if (cnt[v] > n) return 1;
if (!st[v]) {
q.push(v);
st[v] = 1;
}
}
}
}
return 0;
}
int main() {
scanf("%d %d", &n, &m);
memset(h, -1, sizeof h);
while (m--) {
int x, a, b; // X为大小关系描述
scanf("%d %d %d", &x, &a, &b);
// 求最小值,需要最长路,即形如: a>=b+1这样形式的式子
// 表示第 a 个小朋友分到的糖果必须和第 b 个小朋友分到的糖果一样多
// a == b => (a >= b , b >= a) 相等的关系,需要传入两条对称的边,即 a>=b,b>=a,边长为0
if (x == 1) add(a, b, 0), add(b, a, 0);
// 表示第 A 个小朋友分到的糖果必须少于第 B 个小朋友分到的糖果
// a<b => b > a => b >= a+1
if (x == 2) add(a, b, 1);
// 表示第 a 个小朋友分到的糖果必须不少于第 b 个小朋友分到的糖果
// 不少于即大于等于 a >= b
if (x == 3) add(b, a, 0);
// 表示第 a 个小朋友分到的糖果必须多于第 b 个小朋友分到的糖果
// a>b => a >= b+1
if (x == 4) add(b, a, 1);
// 表示第 a 个小朋友分到的糖果必须不多于第 b 个小朋友分到的糖果。
// a<=b => b>=a
if (x == 5) add(a, b, 0);
}
// 重点:需要自己从题意中挖掘出一个性质,即 每个小朋友都要至少一个糖果
// xi >= 1 => xi >= x0 + 1
// 将所有节点与超级源点x0相连
for (int i = 1; i <= n; i++) add(0, i, 1);
if (spfa())
puts("-1");
else {
LL res = 0;
for (int i = 1; i <= n; i++) res += dist[i]; // 累加所有最小值的和
printf("%lld\n", res);
}
return 0;
}