/*
Author: SJ
general
1.shuzu buyao kai xiaole
2.0 1 zhe liangge tepan
3.dfs jide biaoji qidian
4.changdaima jide fenbu tiaoshi
5.yao xihuanshang heihezi
str
1.yongle s.substr(), jide kanyixiashibushikeyi yigeyige shuchu
THINK TWICE, CODE ONCE.
Duo xiang ti, Shao jiao lv.
*/
#include<bits/stdc++.h>
const int N = 5e4 + 10;
using ll = long long;
using ull = unsigned long long;
/*
这道题中, val[x]的含义即x与根节点的距离,
它模三即他与根节点种类的关系
余1剩余类即被根节点吃
余2剩余类即吃根节点
余0剩余类即和根节点同类
只有x, y同一个集合, 才能判断此语句真假
*/
int n, k, fa[N], val[N], ans;
void init() {
for (int i = 1; i <= n; i++) fa[i] = i;
}
int find(int x) {
if (x != fa[x]) {
int t = fa[x];
fa[x] = find(fa[x]);
val[x] += val[fa[x]];
}
return fa[x];
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin >> n >> k;
init();
while (k--) {
int d, x, y;
std::cin >> d >> x >> y;
if (x > n || y > n || (x == y && d == 2)) {
ans++;
continue;
}
int xx = find(x);
int yy = find(y);
if (xx == yy) {
if (d == 1) {
if ((val[x] - val[y]) % 3) ans++;
} else if (d == 2) {
if ((val[x] + 1 - val[y]) % 3) ans++;
}
} else {
if (d == 1) {
fa[yy] = xx;
val[yy] = val[x] - val[y];
while (val[yy] < 0) val[yy] += 3;
} else if (d == 2) {
fa[yy] = xx;
val[yy] = val[x] - val[y] + 1;
while (val[yy] < 0) val[yy] += 3;
}
}
}
// for (int i = 1; i <= 3; i++) {
// std::cout << fa[i] << ' ' << val[i] << "\n";
// }
std::cout << ans;
return 0;
}