#include <bits/stdc++.h>
using namespace std;
const int MAXN(4e5 + 100), INF(0x3f3f3f3f);
struct Node {
  int left, right, lazy;
  long long val1, val2;
} tree[MAXN << 2];
int n, m, clk, pre[MAXN], post[MAXN], id[MAXN], col[MAXN], cc;
vector<int> G[MAXN];
inline int read() {
  int f = 1, x = 0;
  char ch;
  do {
    ch = getchar();
    if (ch == '-') f = -1;
  } while (ch < '0' || ch > '9');
  do {
    x = x * 10 + ch - '0';
    ch = getchar();
  } while (ch >= '0' && ch <= '9');
  return f * x;
}
void pushup(int v) {
  tree[v].val1 = (tree[(v << 1)].val1 | tree[(v << 1 | 1)].val1);
  tree[v].val2 = (tree[(v << 1)].val2 | tree[(v << 1 | 1)].val2);
}
void pushdown(int v) {
  int &lz = tree[v].lazy;
  if (lz) {
    tree[(v << 1)].lazy = tree[(v << 1 | 1)].lazy = lz;
    if (lz <= 30) {
      tree[(v << 1)].val2 = tree[(v << 1 | 1)].val2 = (1 << lz - 1);
      tree[(v << 1)].val1 = tree[(v << 1 | 1)].val1 = 0;
    } else {
      tree[(v << 1)].val2 = tree[(v << 1 | 1)].val2 = 0;
      tree[(v << 1)].val1 = tree[(v << 1 | 1)].val1 = (1 << lz - 31);
    }
  }
  lz = 0;
}
void build(int l, int r, int v) {
  tree[v].left = l;
  tree[v].right = r;
  if (l == r) {
    int idx = id[l];
    if (col[idx] <= 30)
      tree[v].val2 = (1 << col[idx] - 1);
    else
      tree[v].val1 = (1 << col[idx] - 31);
    return;
  }
  int mid = (l + r) >> 1;
  build(l, mid, (v << 1));
  build(mid + 1, r, (v << 1 | 1));
  pushup(v);
}
void update(int l, int r, int v) {
  if (l == tree[v].left && r == tree[v].right) {
    if (cc <= 30) {
      tree[v].val2 = (1 << cc - 1);
      tree[v].val1 = 0;
    } else {
      tree[v].val2 = 0;
      tree[v].val1 = (1 << cc - 31);
    }
    tree[v].lazy = cc;
    return;
  }
  pushdown(v);
  if (l <= tree[(v << 1)].right) {
    if (r <= tree[(v << 1)].right)
      update(l, r, (v << 1));
    else
      update(l, tree[(v << 1)].right, (v << 1));
  }
  if (r >= tree[(v << 1 | 1)].left) {
    if (l >= tree[(v << 1 | 1)].left)
      update(l, r, (v << 1 | 1));
    else
      update(tree[(v << 1 | 1)].left, r, (v << 1 | 1));
  }
  pushup(v);
}
pair<long long, long long> query(int l, int r, int v) {
  if (l == tree[v].left && r == tree[v].right)
    return pair<long long, long long>(tree[v].val2, tree[v].val1);
  pushdown(v);
  if (r <= tree[(v << 1)].right) return query(l, r, (v << 1));
  if (l >= tree[(v << 1 | 1)].left) return query(l, r, (v << 1 | 1));
  pair<long long, long long> res1 = query(l, tree[(v << 1)].right, (v << 1));
  pair<long long, long long> res2 =
      query(tree[(v << 1 | 1)].left, r, (v << 1 | 1));
  pair<long long, long long> ret;
  ret.first = (res1.first | res2.first);
  ret.second = (res1.second | res2.second);
  return ret;
}
void dfs(int u, int p) {
  pre[u] = ++clk;
  id[clk] = u;
  for (int v : G[u])
    if (v != p) dfs(v, u);
  post[u] = clk;
}
void init() {
  n = read();
  m = read();
  for (int i = 1; i <= n; i++) col[i] = read();
  for (int i = 1; i < n; i++) {
    int u = read();
    int v = read();
    G[u].push_back(v);
    G[v].push_back(u);
  }
}
void solve() {
  dfs(1, 0);
  build(1, n, 1);
  for (int i = 1; i <= m; i++) {
    int op = read();
    if (op == 1) {
      int a = read();
      cc = read();
      update(pre[a], post[a], 1);
    } else {
      int a = read();
      pair<long long, long long> res = query(pre[a], post[a], 1);
      int ans =
          __builtin_popcountll(res.first) + __builtin_popcountll(res.second);
      printf("%d\n", ans);
    }
  }
}
int main() {
  {
    init();
    solve();
  }
}
