#include<iostream>
#include<sstream>
#include<algorithm>
#include<cstdio>
#include<string.h>
#include<cctype>
#include<string>
#include<cmath>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
using namespace std;
int n,m; int a[400008];
vector<int> G[400009];
int R[400009];
int L[400009];
int cl[400009];
typedef long long ll;
const int INF = 400009;
struct Tree{
ll c;
int l,r;
int add;
#define add(x) t[x].add
#define c(x) t[x].c
#define l(x) t[x].l
#define r(x) t[x].r
}t[INF<<4];
long long q[INF<<2];
void build(int p,int l,int r){
l(p)=l;r(p)=r;add(p)=0;
if(l==r){
c(p)=1LL<<(cl[l]-1);
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
c(p)=c(p*2)|c(p*2+1);
}
int ct=0;
void dfs(int now,int pre){
L[now]=++ct;
cl[ct]=a[now];
for(int i=0;i<G[now].size();i++){
int u=G[now][i];
if(u==pre) continue;
dfs(u,now);
}
R[now]=ct;
}
void spread(int p){
if(add(p)){
c(p*2)=1LL<<(add(p)-1);
c(p*2+1)=1LL<<(add(p)-1);
add(p*2)=add(p);
add(p*2+1)=add(p);
add(p)=0;
}
}
void update(int st,int L,int R,int color)
{
if(l(st)>=L&&R>=r(st))
{
c(st)=1LL<<(color-1);
add(st)=color;
return;
}
spread(st);
int mid=(l(st)+r(st))>>1;
if(L<=mid)
update(st<<1,L,R,color);
if(R>mid)
update(st<<1|1,L,R,color);
c(st)=c(st*2)|c(st*2+1);
}
long long query(int st,int L,int R)
{
if(l(st)>=L&&R>=r(st))
return c(st);
long long ans=0;
int mid=(l(st)+r(st))>>1;
spread(st);
if(L<=mid)
ans|=query(st<<1,L,R);
if(R>mid)
ans|=query(st<<1|1,L,R);
return ans;
}
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
G[i].clear();
}
for(int i=1;i<=n-1;i++){
int ta,tb;
scanf("%d%d",&ta,&tb);
G[ta].push_back(tb);
G[tb].push_back(ta);
}
dfs(1,-1);
build(1,1,n);
for(int i=1;i<=m;i++){
int ta;
scanf("%d",&ta);
if(ta==1){
int tb,tc;
scanf("%d%d",&ta,&tb);
update(1,L[ta],R[ta],tb);
}
else{
int tb;
scanf("%d",&tb);
ll tem=query(1,L[tb],R[tb]);
int ans=0;
for(int i=0;i<60;i++){
if((tem>>i)&1) ans++;
}
printf("%d\n",ans);
}
}
}
}
#include<iostream>
#include<sstream>
#include<algorithm>
#include<cstdio>
#include<string.h>
#include<cctype>
#include<string>
#include<cmath>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
using namespace std;
int n,m; int a[400008];
vector<int> G[400009];
int R[400009];
int L[400009];
int cl[400009];
typedef long long ll;
const int INF = 400009;
struct Tree{
ll c;
int add;
int l,r;
#define c(x) t[x].c
#define l(x) t[x].l
#define r(x) t[x].r
#define add(x) t[x].add
}t[INF<<4];
long long q[INF<<2];
void build(int p,int l,int r){
l(p)=l;r(p)=r;add(p)=0;
if(l==r){
c(p)=1LL<<(cl[l]-1);
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
c(p)=c(p*2)|c(p*2+1);
}
int ct=0;
void dfs(int now,int pre){
L[now]=++ct;
cl[ct]=a[now];
for(int i=0;i<G[now].size();i++){
int u=G[now][i];
if(u==pre) continue;
dfs(u,now);
}
R[now]=ct;
}
void spread(int p){
if(add(p)){
c(p*2)=(1LL<<(add(p)-1));
c(p*2+1)=(1LL<<(add(p)-1));
add(p*2)=add(p);
add(p*2+1)=add(p);
add(p)=0;
}
}
void update(int st,int L,int R,int color)
{
if(l(st)>=L&&R>=r(st))
{
c(st)=1LL<<(color-1);
add(st)=color;
return;
}
spread(st);
int mid=(l(st)+r(st))>>1;
if(L<=mid)
update(st<<1,L,R,color);
if(R>mid)
update(st<<1|1,L,R,color);
c(st)=c(st*2)|c(st*2+1);
}
long long query(int st,int L,int R)
{
if(L<=l(st)&&R>=r(st))
return c(st);
spread(st);
long long ans=0;
int mid=(l(st)+r(st))>>1;
if(L<=mid)
ans|=query(st<<1,L,R);
if(R>mid)
ans|=query(st<<1|1,L,R);
return ans;
}
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
G[i].clear();
}
for(int i=1;i<=n-1;i++){
int ta,tb;
scanf("%d%d",&ta,&tb);
G[ta].push_back(tb);
G[tb].push_back(ta);
}
dfs(1,-1);
build(1,1,n);
for(int i=1;i<=m;i++){
int ta;
scanf("%d",&ta);
if(ta==1){
int tb,tc;
scanf("%d%d",&ta,&tb);
update(1,L[ta],R[ta],tb);
}
else{
int tb;
scanf("%d",&tb);
ll tem=query(1,L[tb],R[tb]);
int ans=0;
for(int i=0;i<60;i++){
if((1ll<<i)&tem) ans++;
}
printf("%d\n",ans);
}
}
}
}