#include<bits/stdc++.h>
using namespace std;
//three arrays to maintain the hierarchy, eats represents the root node of prey, eaten represents the root node of predator
int dsu[60000],eats[60000],eaten[60000],siz[60000];
//initialising function
void init(int n){
for(int i=0;i<=n;i++){
dsu[i]=i;
eats[i]=eaten[i]=0;
siz[i]=1;
}
}
//typical compressed root find function
int root_find(int x){
while(x!=dsu[x]){
dsu[x]=dsu[dsu[x]];
x=dsu[x];
}
return x;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t,n,k,x,y,s,d;
cin>>t;
while(t--){
cin>>n>>k;
s=0;
init(n);
while(k--){
cin>>d>>x>>y;
//if x>n or y>n
if(x>n||y>n){
s++;
continue;
}
x=root_find(x);
y=root_find(y);
eats[x]=root_find(eats[x]);
eats[y]=root_find(eats[y]);
eaten[x]=root_find(eaten[x]);
eaten[y]=root_find(eaten[y]);
//if x==y, nothing needs to be processed whatsoever
if(d==1&&x!=y){
if(eats[x]==eaten[y]&&eats[x]!=0) //if prey of x is same as predator of y, and prey of x is not empty
s++;
else if(eats[y]==eaten[x]&&eats[y]!=0) //if prey of y is same as predator of x and predator of y is not empty
s++;
else if(eats[y]==x) //if prey of y is same as x
s++;
else if(eats[x]==y) //if prey of x is same as y
s++;
else if(eaten[x]==y) //if predator of x is same as y
s++;
else if(eaten[y]==x) //if predator of y is same as x
s++;
else{
//all possible contradictions are hereby covered
//now we combine (x,y) , (eats[x],eats[y]) & (eaten[x],eaten[y])
if(siz[eats[x]]>=siz[eats[y]]&&eats[x]!=0&&eats[y]!=0){
dsu[eats[y]]=eats[x];
siz[eats[x]]+=siz[eats[y]];
}
else if(eats[x]!=0&&eats[y]!=0){
dsu[eats[x]]=eats[y];
siz[eats[y]]+=siz[eats[x]];
}
else if(eats[y]==0&&eats[x]!=0)
eats[y]=x;
else if(eats[x]==0&&eats[y]!=0)
eats[x]=y;
if(siz[eaten[x]]>=siz[eaten[y]]&&eaten[x]!=0&&eaten[y]!=0){
dsu[eaten[y]]=eats[y];
siz[eaten[y]]+=siz[eaten[x]];
}
else if(eaten[x]!=0&&eaten[y]!=0){
dsu[eaten[x]]=eaten[y];
siz[eaten[y]]+=siz[eaten[x]];
}
else if(eaten[y]==0&&eaten[x]!=0)
eaten[y]=x;
else if(eaten[x]==0&&eaten[y]!=0)
eaten[x]=y;
if(siz[x]>=siz[y]){
siz[x]+=siz[y];
dsu[y]=x;
}
else{
siz[y]+=siz[x];
dsu[x]=y;
}
}
}
else if(d==2&&eaten[y]!=x&&eats[x]!=y){
//if x is same as y or y eats x
if(x==y)
s++;
else if(eats[y]==x)
s++;
else if(eaten[x]==y)
s++;
else{
// combine (eats[x],y),(eats[y],eaten[x]) & (eaten[y],x)
if(siz[eats[x]]>=siz[y]&&eats[x]!=0){
siz[eats[x]]+=siz[y];
dsu[y]=eats[x];
}
else if(eats[x]!=0){
siz[y]+=siz[eats[x]];
dsu[eats[x]]=y;
}
else
eats[x]=y;
if(siz[eaten[y]]>=siz[x]&&eaten[y]!=0){
siz[eaten[y]]+=siz[x];
dsu[x]=eaten[y];
}
else if(eaten[y]!=0){
siz[x]+=siz[eaten[y]];
dsu[eaten[y]]=x;
}
else
eaten[y]=x;
if(siz[eaten[x]]>=siz[eats[y]]&&eaten[x]!=0&&eats[y]!=0){
siz[eaten[x]]+=siz[eats[y]];
dsu[eats[y]]=eaten[x];
}
else if(eaten[x]!=0&&eats[y]!=0){
siz[eats[y]]+=siz[eaten[x]];
dsu[eaten[x]]=eaten[y];
}
else if(eaten[x]==0&&eats[y]!=0)
eaten[x]=y;
else if(eaten[x]!=0&&eats[y]==0)
eats[y]=eaten[x];
}
}
}
//all incorrect statements.
cout<<s<<"\n";
}
return 0;
}