#include <bits/stdc++.h>
using namespace std;
const double EPS = 1e-9;
const int INF = 0x7f7f7f7f;
const double PI = acos(-1.0);
template <class T>
inline T _abs(T n) {
  return ((n) < 0 ? -(n) : (n));
}
template <class T>
inline T _max(T a, T b) {
  return (!((a) < (b)) ? (a) : (b));
}
template <class T>
inline T _min(T a, T b) {
  return (((a) < (b)) ? (a) : (b));
}
template <class T>
inline T gcd(T a, T b) {
  return (b) == 0 ? (a) : gcd((b), ((a) % (b)));
}
template <class T>
inline T lcm(T a, T b) {
  return ((a) / gcd((a), (b)) * (b));
}
struct debugger {
  template <typename T>
  debugger& operator,(const T& v) {
    cerr << v << " ";
    return *this;
  }
} dbg;
int t, n, m;
int arr[400005];
bool mark[400005];
int in[400005], out[400005], org[400005];
vector<int> adj[400005];
struct info {
  int tot;
  long long mask;
  int prop;
  info() {
    prop = 0;
    tot = 0;
    mask = 0;
  }
} tree[400005 * 3];
info dummy;
info gett(info a, info b) {
  info x;
  x.mask = a.mask | b.mask;
  x.tot = __builtin_popcountll(x.mask);
  return x;
}
void init(int node, int b, int e) {
  if (b == e) {
    tree[node].mask = 1LL << arr[org[b]];
    tree[node].tot = __builtin_popcountll(tree[node].mask);
    return;
  }
  int Left = node * 2;
  int Right = node * 2 + 1;
  int mid = (b + e) / 2;
  init(Left, b, mid);
  init(Right, mid + 1, e);
  tree[node] = gett(tree[Left], tree[Right]);
}
void propagate(int node, int b, int e) {
  int Left = node * 2;
  int Right = node * 2 + 1;
  tree[Left] = tree[node];
  tree[Right] = tree[node];
  tree[node].prop = 0;
}
info query(int node, int b, int e, int i, int j) {
  if (i > e || j < b) return dummy;
  if (b >= i && e <= j) {
    return tree[node];
  }
  if (tree[node].prop) propagate(node, b, e);
  int Left = node * 2;
  int Right = node * 2 + 1;
  int mid = (b + e) / 2;
  info p1 = query(Left, b, mid, i, j);
  info p2 = query(Right, mid + 1, e, i, j);
  return gett(p1, p2);
}
void update(int node, int b, int e, int i, int j, int newvalue) {
  if (i > e || j < b) return;
  if (i > e || j < b) return;
  if (b >= i && e <= j) {
    tree[node] = dummy;
    tree[node].prop = 1;
    tree[node].mask = 1LL << newvalue;
    tree[node].tot = 1;
    return;
  }
  if (tree[node].prop) propagate(node, b, e);
  int Left = node * 2;
  int Right = node * 2 + 1;
  int mid = (b + e) / 2;
  update(Left, b, mid, i, j, newvalue);
  update(Right, mid + 1, e, i, j, newvalue);
  tree[node] = gett(tree[Left], tree[Right]);
}
int tme = 1;
void dfs(int src) {
  in[src] = tme;
  org[tme] = src;
  mark[src] = 1;
  int sz = adj[src].size();
  for (int i = 0; i < (sz); i++) {
    if (!mark[adj[src][i]]) {
      tme++;
      dfs(adj[src][i]);
    }
  }
  out[src] = tme;
}
int main() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= (n); i++) scanf("%d", &arr[i]);
  int a, b;
  for (int i = 1; i <= (n - 1); i++) {
    scanf("%d%d", &a, &b);
    adj[a].push_back(b);
    adj[b].push_back(a);
  }
  memset(mark, 0, sizeof(mark));
  for (int i = 1; i <= (n); i++) {
    if (!mark[i]) dfs(i);
  }
  int c;
  init(1, 1, n);
  for (int i = 1; i <= (m); i++) {
    scanf("%d%d", &a, &b);
    if (a == 1) {
      scanf("%d", &c);
      update(1, 1, n, in[b], out[b], c);
    } else {
      printf("%d\n", query(1, 1, n, in[b], out[b]).tot);
    }
  }
  return 0;
}
