#include <bits/stdc++.h>
using namespace std;
long long tree[1200001];
int tempo = 0;
int c[400010], l[400010], r[400010], lazy[1200001], n, id[400010];
void relaxa(int no, int esq, int dir) {
  int &v = lazy[no];
  if (v == 0) return;
  tree[no] = (1ULL << v);
  if (esq != dir) {
    lazy[no * 2] = v;
    lazy[no * 2 + 1] = v;
  }
  v = 0;
}
void build(int no, int esq, int dir) {
  if (esq == dir) {
    tree[no] = (1ULL << c[id[esq]]);
    return;
  }
  int meio = (esq + dir) / 2;
  build(no * 2, esq, meio);
  build(no * 2 + 1, meio + 1, dir);
  tree[no] = tree[no * 2] | tree[no * 2 + 1];
}
void update(int no, int esq, int dir, int l, int r, int cor) {
  relaxa(no, esq, dir);
  if (esq > dir || esq > r || dir < l) return;
  if (l <= esq && dir <= r) {
    lazy[no] = cor;
    relaxa(no, esq, dir);
    return;
  }
  int meio = (esq + dir) / 2;
  update(no * 2, esq, meio, l, r, cor);
  update(no * 2 + 1, meio + 1, dir, l, r, cor);
  tree[no] = tree[no * 2] | tree[no * 2 + 1];
}
long long query(int no, int esq, int dir, int l, int r) {
  relaxa(no, esq, dir);
  if (esq > dir || esq > r || dir < l) return 0;
  if (l <= esq && dir <= r) return tree[no];
  int meio = (esq + dir) / 2;
  return query(no * 2, esq, meio, l, r) |
         query(no * 2 + 1, meio + 1, dir, l, r);
}
vector<int> adj[400010];
void dfs(int u, int p) {
  tempo++;
  l[u] = tempo;
  id[tempo] = u;
  for (int v : adj[u]) {
    if (v == p) continue;
    dfs(v, u);
  }
  r[u] = tempo;
}
int main() {
  int m;
  scanf("%d %d", &n, &m);
  for (int i = 1; i <= n; i++) scanf("%d", &c[i]);
  for (int i = 1; i < n; i++) {
    int a, b;
    scanf("%d %d", &a, &b);
    adj[a].push_back(b);
    adj[b].push_back(a);
  }
  dfs(1, 0);
  build(1, 1, n);
  while (m--) {
    int op;
    scanf("%d", &op);
    if (op == 1) {
      int v, cor;
      scanf("%d %d", &v, &cor);
      update(1, 1, n, l[v], r[v], cor);
    } else {
      int v;
      scanf("%d", &v);
      printf("%d\n", __builtin_popcountll(query(1, 1, n, l[v], r[v])));
    }
  }
  return 0;
}
