#include<bits/stdc++.h>
using namespace std;
#define debug(x) cerr<<#x<<' '<<x<<endl
/* --------------- fast io --------------- */ // begin
namespace Fread {
const int SIZE = 1 << 26;
char buf[SIZE], *S, *T;
inline char getchar() {
if (S == T) {
T = (S = buf) + fread(buf, 1, SIZE, stdin);
if (S == T) return '\n';
}
return *S++;
}
} // namespace Fread
namespace Fwrite {
const int SIZE = 1 << 26;
char buf[SIZE], *S = buf, *T = buf + SIZE;
inline void flush() {
fwrite(buf, 1, S - buf, stdout);
S = buf;
}
inline void putchar(char c) {
*S++ = c;
if (S == T) flush();
}
struct NTR {
~ NTR() { flush(); }
} ztr;
} // namespace Fwrite
#ifdef ONLINE_JUDGE
#define getchar Fread :: getchar
#define putchar Fwrite :: putchar
#endif
namespace Fastio {
struct Reader {
template<typename T>
Reader& operator >> (T& x) {
char c = getchar();
T f = 1;
while (c < '0' || c > '9') {
if (c == '-') f = -1;
c = getchar();
}
x = 0;
while (c >= '0' && c <= '9') {
x = (x * 10 + (c - '0'));
c = getchar();
}
x *= f;
return *this;
}
Reader& operator >> (char& c) {
c = getchar();
while (c == '\n' || c == ' ') c = getchar();
return *this;
}
Reader& operator >> (char* str) {
int len = 0;
char c = getchar();
while (c == '\n' || c == ' ') c = getchar();
while (c != '\n' && c != ' ') {
str[len++] = c;
c = getchar();
}
str[len] = '\0';
return *this;
}
Reader(){}
} cin;
const char endl = '\n';
struct Writer {
template<typename T>
Writer& operator << (T x) {
if (x == 0) { putchar('0'); return *this; }
if (x < 0) { putchar('-'); x = -x; }
static int sta[45];
int top = 0;
while (x) { sta[++top] = x % 10; x /= 10; }
while (top) { putchar(sta[top] + '0'); --top; }
return *this;
}
Writer& operator << (char c) {
putchar(c);
return *this;
}
Writer& operator << (char* str) {
int cur = 0;
while (str[cur]) putchar(str[cur++]);
return *this;
}
Writer& operator << (const char* str) {
int cur = 0;
while (str[cur]) putchar(str[cur++]);
return *this;
}
Writer(){}
} cout;
} // namespace Fastio
#define cin Fastio :: cin
#define cout Fastio :: cout
#define endl Fastio :: endl
/* --------------- fast io --------------- */ // end
#define maxn 100010
int n,m,T;
int x,y,op;
int dfn[maxn],top[maxn],cnt;
int fa[maxn],siz[maxn],son[maxn],dep[maxn];
int head[maxn],Next[maxn<<1],ver[maxn<<1],tot;
void add(int x,int y){
ver[++tot]=y;
Next[tot]=head[x];
head[x]=tot;
}
void dfs1(int x){
siz[x]=1;
for(int i=head[x];i;i=Next[i]){
int y=ver[i];
if(dep[y])continue;
dep[y]=dep[x]+1;
fa[y]=x;
dfs1(y);
siz[x]+=siz[y];
if(siz[son[x]]<siz[y])son[x]=y;
}
}
void dfs2(int x,int t){
dfn[x]=++cnt;
top[x]=t;
if(!son[x])return;
dfs2(son[x],t);
for(int i=head[x];i;i=Next[i])
if(ver[i]!=fa[x]&&ver[i]!=son[x])dfs2(ver[i],ver[i]);
}
struct point{
int l,r;
mutable int v;
point(int ll,int rr,int vv):l(ll),r(rr),v(vv){}
bool inline operator<(point x)const{return l<x.l;}
};
#define Iter set<point>::iterator
set<point>s;
Iter split(int x){
if(x>n)return s.end();
Iter it=--s.upper_bound(point(x,0,0));
if(it->l==x)return it;
int l=it->l,r=it->r,v=it->v;
s.erase(it);
s.insert(point(l,x-1,v));
return s.insert(point(x,r,v)).first;
}
void assign(int l,int r,int v){
Iter itr=split(r+1),itl=split(l);
s.erase(itl,itr);
s.insert(point(l,r,v));
}
int ask(int k1,int l,int r,int k2){
Iter itr=split(r+1),itl=split(l),tmp=itr;
--tmp;
assert(tmp!=itr);
int ans=0;
ans+=k2&&(tmp->v==k2);
for(;itl!=itr;++itl){
if(k1&&(k1==itl->v))ans++;
if(itl->v)ans+=itl->r-itl->l;
k1=itl->v;
}
return ans;
}
int get(int x){
return s.lower_bound(point(x,0,0))->v;
}
void change(int x,int y,int col){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
assign(dfn[top[x]],dfn[x],col);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
assign(dfn[x],dfn[y],col);
}
int qry(int x,int y){
int lx=0,ly=0;
int ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y),swap(lx,ly);
ans+=ask(0,dfn[top[x]],dfn[x],lx);
lx=get(dfn[top[x]]);
// cout<<"#"<<top[x]<<' '<<get(top[x])<<endl;
x=fa[top[x]];
}
// cout<<"%"<<lx<<" "<<x<<' '<<ly<<" "<<y<<endl;
// cout<<"@"<<ans<<endl;
if(dep[x]>dep[y])swap(x,y),swap(lx,ly);
ans+=ask(lx,dfn[x],dfn[y],ly);
return ans;
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("edge5.in","r",stdin);
freopen("testdata.out","w",stdout);
#endif
srand(time(NULL));
for(cin>>T;T;T--){
memset(head,0,sizeof head);
s.clear();
tot=1,cnt=0;
memset(fa,0,sizeof fa);
memset(dep,0,sizeof dep);
memset(son,0,sizeof son);
cin>>n>>m;
s.insert(point(1,n,0));
for(int i=1;i<n;i++){
cin>>x>>y;
add(x,y),add(y,x);
}
int rt=rand()%n+1;
dep[rt]=1,dfs1(rt);
dfs2(rt,rt);
// for(int i=1;i<=n;i++)cout<<dfn[i]<<' ';cout<<endl;
while(m--){
cin>>op>>x>>y;
if(op==1)change(x,y,m);
else cout<<qry(x,y)<<endl;
// puts("Start");
// for(Iter it=s.begin();it!=s.end();++it)cout<<it->l<<" "<<it->r<<' '<<it->v<<endl;
// puts("End");
}
}
#ifndef ONLINE_JUDGE
cerr<<endl<<(double)clock()/CLOCKS_PER_SEC;
#endif
}
TLE80珂朵莉爬树是真的慢草,主要是树链上切了太多链了,但还是想请dalao卡常