记录
#include <iostream>
#include <vector>
#include <queue>
#include <list>
#include <map>
using namespace std;
struct Edge
{
int to, dis;
Edge *nextEdge;
};
struct Data_Edge
{
int X, A, B;
};
list<Edge> edges;
vector<Edge *> head;
vector<int> father;
vector<Data_Edge> records;
vector<bool> data_fail;
vector<int> inCnt;
vector<int> DP;
map<pair<int, int>, bool> appear_dis_0;
queue<int> que;
int N, K;
void AddEdge(const int &from, const int &to, const int &dis)
{
edges.push_back({to, dis, head[from]});
head[from] = &edges.back();
}
int FindRoot(const int &n)
{
return father[n] ? father[n] = FindRoot(father[n]) : n;
}
void UnionNode(int x, int y)
{
x = FindRoot(x);
y = FindRoot(y);
if (x != y)
{
father[x] = y;
}
}
void Topology()
{
while (!que.empty())
{
int top = que.front();
que.pop();
for (Edge *e = head[top]; e != NULL; e = e->nextEdge)
{
DP[e->to] = max(DP[e->to], DP[top] + e->dis);
inCnt[e->to]--;
if (inCnt[e->to] == 0)
{
que.push(e->to);
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> N >> K;
DP.assign(N + 2, 0);
inCnt.assign(N + 1, 0);
father.assign(N + 1, 0);
head.assign(N + 1, NULL);
for (int i = 0, x, a, b; i < K; i++)
{
cin >> x >> a >> b;
if (x == 1)
{
UnionNode(a, b);
}
else
{
switch (x)
{
case 3:
appear_dis_0[{b, a}] = 1;
break;
case 5:
appear_dis_0[{a, b}] = 1;
break;
default:
break;
}
records.push_back({x, a, b});
}
}
data_fail.assign(records.size(), 0);
for (size_t i = 0; i < records.size(); i++)
{
switch (records[i].X)
{
case 3:
if (appear_dis_0[{records[i].A, records[i].B}])
{
data_fail[i] = true;
UnionNode(records[i].A, records[i].B);
}
break;
case 5:
if (appear_dis_0[{records[i].B, records[i].A}])
{
data_fail[i] = true;
UnionNode(records[i].A, records[i].B);
}
break;
default:
break;
}
}
for (size_t i = 0; i < records.size(); i++)
{
if (data_fail[i] == 0)
{
switch (records[i].X)
{
case 2:
{
int root_a = FindRoot(records[i].A);
int root_b = FindRoot(records[i].B);
if (root_a == root_b)
{
cout << -1;
return 0;
}
AddEdge(root_a, root_b, 1);
inCnt[root_b]++;
break;
}
case 3:
{
int root_a = FindRoot(records[i].A);
int root_b = FindRoot(records[i].B);
if (root_a == root_b)
{
break;
}
AddEdge(root_b, root_a, 0);
inCnt[root_a]++;
break;
}
case 4:
{
int root_a = FindRoot(records[i].A);
int root_b = FindRoot(records[i].B);
if (root_a == root_b)
{
cout << -1;
return 0;
}
AddEdge(root_b, root_a, 1);
inCnt[root_a]++;
break;
}
case 5:
{
int root_a = FindRoot(records[i].A);
int root_b = FindRoot(records[i].B);
if (root_a == root_b)
{
break;
}
AddEdge(root_a, root_b, 0);
inCnt[root_b]++;
break;
}
default:
break;
}
}
}
for (int i = 1; i <= N; i++)
{
if (father[i] == 0 && inCnt[i] == 0)
{
que.push(i);
DP[i] = 1;
}
}
Topology();
int Ans = 0;
for (int i = 1; i <= N; i++)
{
Ans += DP[FindRoot(i)];
if (father[i] == 0 && DP[i] == 0)
{
cout << -1;
return 0;
}
}
cout << Ans;
return 0;
}