#include <bits/stdc++.h>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
inline bool ok(int x) {
  int limit = sqrt(x) + 1;
  for (int i = 2; i <= limit && i < x; ++i)
    if (x % i == 0) return false;
  return true;
}
struct Edge {
  int to, nx;
  inline Edge() {}
  inline Edge(int to, int nx) : to(to), nx(nx) {}
} edge[100100 << 1];
int n, m, q;
int head[100100], tot, cnt, pos;
int ord[100100], ford[100100], son[100100];
int arr[100100];
bitset<1010> stand, prime;
inline void up(int &x) {
  if (x >= m) x -= m;
}
inline void Init() {
  memset(head, -1, sizeof head);
  tot = 0;
  cnt = 0;
  stand = prime = 0;
  stand[0] = stand[1] = 1;
  for (int i = 2; i < m; ++i) {
    stand[i] = 1;
    if (ok(i)) prime[i] = 1;
  }
}
inline void addedge(int u, int v) {
  edge[++tot] = Edge(v, head[u]);
  head[u] = tot;
  edge[++tot] = Edge(u, head[v]);
  head[v] = tot;
}
inline void DFS(int u, int pre) {
  ord[u] = ++cnt;
  ford[cnt] = u;
  for (int it = head[u]; ~it; it = edge[it].nx) {
    int v = edge[it].to;
    if (v == pre) continue;
    DFS(v, u);
  }
  son[u] = cnt;
}
struct node {
  int l, r;
  int lazy;
  bitset<1010> b;
  inline node() {}
  inline node(int _l, int _r) {
    l = _l;
    r = _r;
    b = 0;
    lazy = 0;
  }
} tree[100100 << 2];
inline void pushup(int id) {
  tree[id].b = tree[id << 1].b | tree[id << 1 | 1].b;
}
inline void tran(node &r, int lazy) {
  bitset<1010> tmp1, tmp2;
  tmp1 = tmp2 = 0;
  tmp1 = (r.b >> (m - lazy));
  tmp2 = (r.b << lazy);
  r.b = (tmp1 | tmp2) & stand;
}
inline void pushdown(int id) {
  if (tree[id].l >= tree[id].r) return;
  if (tree[id].lazy) {
    int lazy = tree[id].lazy;
    tree[id].lazy = 0;
    up(tree[id << 1].lazy += lazy);
    up(tree[id << 1 | 1].lazy += lazy);
    tran(tree[id << 1], lazy);
    tran(tree[id << 1 | 1], lazy);
  }
}
inline void build(int id, int l, int r) {
  tree[id] = node(l, r);
  if (l == r) {
    tree[id].b[arr[ford[l]]] = 1;
    return;
  }
  int mid = (l + r) >> 1;
  build(id << 1, l, mid);
  build(id << 1 | 1, mid + 1, r);
  pushup(id);
}
inline void update(int id, int l, int r, int val) {
  if (tree[id].l >= l && tree[id].r <= r) {
    up(tree[id].lazy += val);
    tran(tree[id], val);
    return;
  }
  pushdown(id);
  int mid = (tree[id].l + tree[id].r) >> 1;
  if (l <= mid) update(id << 1, l, r, val);
  if (r > mid) update(id << 1 | 1, l, r, val);
  pushup(id);
}
bitset<1010> ans;
inline void query(int id, int l, int r) {
  if (tree[id].l >= l && tree[id].r <= r) {
    ans |= tree[id].b;
    return;
  }
  pushdown(id);
  int mid = (tree[id].l + tree[id].r) >> 1;
  if (l <= mid) query(id << 1, l, r);
  if (r > mid) query(id << 1 | 1, l, r);
  pushup(id);
}
inline void Run() {
  while (scanf("%d%d", &n, &m) != EOF) {
    Init();
    for (int i = 1; i <= n; ++i) scanf("%d", arr + i), arr[i] %= m;
    for (int i = 1, u, v; i < n; ++i) {
      scanf("%d%d", &u, &v);
      addedge(u, v);
    }
    DFS(1, 1);
    build(1, 1, n);
    scanf("%d", &q);
    int op, v, x;
    while (q--) {
      scanf("%d", &op);
      if (op == 1) {
        scanf("%d%d", &v, &x);
        x %= m;
        update(1, ord[v], son[v], x);
      } else {
        scanf("%d", &v);
        ans = 0;
        query(1, ord[v], son[v]);
        printf("%d\n", (ans & prime).count());
      }
    }
  }
}
int main() {
  Run();
  return 0;
}
