// Problem: CF620E New Year Tree
// Memory Limit: 250 MB
// Time Limit: 3000 ms
// Powered by CP Editor (https://github.com/cpeditor/cpeditor)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 4e5 + 50;
bitset <61> Ans;//注意一定要定义与下面的相同的长度,不然很不方便
int n,Q,tot = 0,now = 0;
int start[MAXN];
int data[MAXN],siz[MAXN],son[MAXN],deep[MAXN],fa[MAXN];
int dfn[MAXN],dfn_id[MAXN];

struct SegmentTree {
    int l,r;
    bitset <61> B;
    int F;
} T[MAXN * 4];

struct Edge {
    int next,to;
    void add(int from,int To) {next = start[from], to = To , start[from] = tot;}
} edge[MAXN * 2];

inline int read() {
    int x = 0 , flag = 1;
    char ch = getchar();
    for( ; ch > '9' || ch < '0' ; ch = getchar());
    for( ; ch >= '0' && ch <= '9' ; ch = getchar()) x = (x << 3) + (x << 1) + ch - '0';
    return x * flag;
}

int DFS1(int x,int from) {//求DFS序
    siz[x] = 1, son[x] = 0;
    deep[x] = deep[from] + 1 , fa[x] = from;
    dfn[x] = ++now , dfn_id[now] = x;
    for(int i = start[x] ; i ; i = edge[i].next) {
        int to = edge[i].to;
        if(to == from) continue;
        int v = DFS1(to , x);
        if(siz[v] > siz[son[x]]) son[x] = to;
        siz[x] += v;
    }
    return siz[x];
}

void build(int x,int l,int r) {
    T[x].l = l , T[x].r = r;
    T[x].B = 0ll, T[x].F = 0ll;
    if(l == r) {
        T[x].B[data[dfn_id[l]]] = 1;//dfn_id表示的是Dfn序对应的原数组的下标
        return ;
    }
    int mid = (l + r) >> 1;
    build(x << 1 , l , mid);
    build(x << 1 | 1 , mid + 1 , r);
    T[x].B = T[x << 1].B | T[x << 1 | 1].B;//用或运算连接
    return ;
}

void update(int x,int k) {
    T[x].B.reset();//因为全部覆盖掉了,所以清空
    T[x].B[k] = 1;
    T[x].F = k;
    return ;
}

void pushdown(int x) {//下传标记
    if(T[x].F == 0ll) return ;
    update(x << 1 | 1 , T[x].F);//这个F就是被覆盖的标记
    update(x << 1 , T[x].F);
    T[x].F = 0ll;
    return ;
}

void change(int x,int l,int r,int k) {
    if(T[x].l >= l && T[x].r <= r) {
        update(x, k);
        return ;
    }
    pushdown(x);
    int mid = (T[x].l + T[x].r) >> 1;
    if(l <= mid) change(x << 1 , l , r , k);
    if(r  > mid) change(x << 1 | 1 , l , r , k);
    T[x].B = T[x << 1].B | T[x << 1 | 1].B;
    return ;
}

void GetAns(int x,int l,int r) {// 统计答案,对于涉及到的区间用 "|" 运算来取得答案
    if(T[x].l >= l && T[x].r <= r) {
        Ans |= T[x].B;//前文提到了两个 bitset 类型的数组可以直接用位运算符号连接
        return ;
    }
    pushdown(x);
    int mid = (T[x].l + T[x].r) >> 1;
    if(l <= mid) GetAns(x << 1 , l , r );
    if(r >  mid) GetAns(x << 1 | 1 , l , r);
    return ;
}

int main() {
    n = read() , Q = read();
    for(int i = 1 ; i <= n ; i ++) data[i] = read();
    for(int i = 1 ; i <= n - 1 ; i ++) {
        int u = read() , v = read();
        edge[++tot].add(u,v);
        edge[++tot].add(v,u);
    }
    DFS1(1,0);//预处理
    build(1 , 1 , n);
    while(Q --) {
        int op = read() , u = read() , c;
        if(op == 1) c = read();
        if(op == 1) change(1 , dfn[u] , dfn[u] + siz[u] - 1 , c);//子树修改
        else {
            Ans.reset();//这个是将 bitset 数组清空的函数
            GetAns(1 , dfn[u] , dfn[u] + siz[u] - 1);
            printf("%d\n",Ans.count());//bitset 的 count函数就是统计1的个数
        }
    }
    return 0;
}