#include<bits/stdc++.h>
#define int long long
using namespace std;
const int M=3e6+10;
const int N=2e5+10;
long long tree[2000100],lazy[2000100],ans;
int n,q,v,u,opt,x,c,k;
int dfn[N],sz[N],hd[N],cnt,num,jsq,id[N];
bool vis[N];
set<int> s[N];
struct st{
int to,next;
}edge[400010];
void add(int u,int v){
edge[++cnt].to=v;
edge[cnt].next=hd[u];
hd[u]=cnt;
return ;
}
void dfs(int now){
vis[now]=true;
dfn[now]=++num;
sz[dfn[now]]=1;
for (int i=hd[now];i;i=edge[i].next){
if (vis[edge[i].to])continue;
dfs(edge[i].to);
sz[dfn[now]]+=sz[dfn[edge[i].to]];
}
return ;
}
void update(int now,int l,int r,int x,int y,int z){
if (x<=l&&y>=r){
lazy[now]+=z;
tree[now]+=z*(r-l+1);
return ;
}
int mid=(l+r)>>1;
lazy[now<<1]+=lazy[now];
tree[now<<1]+=lazy[now]*(mid-l+1);
lazy[now<<1|1]+=lazy[now];
tree[now<<1|1]+=lazy[now]*(r-mid);
lazy[now]=0;
if (x<=mid)update(now<<1,l,mid,x,y,z);
if (y>mid)update(now<<1|1,mid+1,r,x,y,z);
tree[now]=tree[now<<1]+tree[now<<1|1];
return ;
}
void query(int now,int l,int r,int x,int y){
if (x<=l&&y>=r){
ans+=tree[now];
return ;
}
int mid=(l+r)>>1;
lazy[now<<1]+=lazy[now];
tree[now<<1]+=lazy[now]*(mid-l+1);
lazy[now<<1|1]+=lazy[now];
tree[now<<1|1]+=lazy[now]*(r-mid);
lazy[now]=0;
if (x<=mid)query(now<<1,l,mid,x,y);
if (y>mid)query(now<<1|1,mid+1,r,x,y);
tree[now]=tree[now<<1]+tree[now<<1|1];
return ;
}
signed main(){
scanf("%lld%lld",&n,&q);
for (int i=1;i<n;i++){
scanf("%lld%lld",&u,&v);
add(u,v);
add(v,u);
}
dfs(1);
for (int i=1;i<=q;i++){
scanf("%lld",&opt);
if (opt==1){
scanf("%lld%lld",&x,&c);
x=dfn[x];
auto p=s[c].upper_bound(x);
if (p!=s[c].end()&&p!=s[c].begin()){
k=*(--p);
if (k+sz[k]-1>=x&&k>=x){
continue;
}
}
p=s[c].lower_bound(x);
while (p!=s[c].end()){
k=*p;
if (x+sz[x]-1>=k){
update(1,1,n,k,k+sz[k]-1,-1);
s[c].erase(p);
}else break;
p=s[c].upper_bound(x);
}
s[c].insert(x);
update(1,1,n,x,x+sz[x]-1,1);
}else{
scanf("%lld",&x);
x=dfn[x];
ans=0ll;
query(1,1,n,x,x+sz[x]-1);
printf("%lld\n",ans);
}
}
return 0;
}