#include <bits/stdc++.h>
using namespace std;
const long long MAXN = (1 << 18);
long long n, m;
long long value[MAXN], a[MAXN];
struct node {
  long long lazy;
  bitset<1000> mask;
  node() { lazy = 0; }
  node(long long val) {
    lazy = 0;
    mask.set(val);
  }
};
node temp, broken;
node merge(node l, node r) {
  temp.mask = l.mask | r.mask;
  temp.lazy = 0;
  return temp;
}
bitset<1000> helper_m;
bitset<1000> fh, sh;
struct segment_tree {
  node tr[4 * MAXN];
  void lazy(long long l, long long r, long long idx) {
    tr[idx].lazy %= m;
    if (tr[idx].lazy) {
      fh = (tr[idx].mask >> (m - tr[idx].lazy)) & helper_m;
      sh = (tr[idx].mask << (tr[idx].lazy)) & helper_m;
      tr[idx].mask = fh | sh;
      if (l != r) {
        tr[2 * idx + 1].lazy += tr[idx].lazy;
        tr[2 * idx + 2].lazy += tr[idx].lazy;
      }
      tr[idx].lazy = 0;
    }
  }
  void init(long long l, long long r, long long idx) {
    if (l == r) {
      tr[idx] = node(value[l] % m);
      return;
    }
    long long mid = (l + r) >> 1;
    init(l, mid, 2 * idx + 1);
    init(mid + 1, r, 2 * idx + 2);
    tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);
  }
  void update(long long qL, long long qR, long long val, long long l,
              long long r, long long idx) {
    lazy(l, r, idx);
    if (l > qR || r < qL) return;
    if (qL <= l && r <= qR) {
      tr[idx].lazy += val;
      lazy(l, r, idx);
      return;
    }
    long long mid = (l + r) >> 1;
    update(qL, qR, val, l, mid, 2 * idx + 1);
    update(qL, qR, val, mid + 1, r, 2 * idx + 2);
    tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);
  }
  node query(long long qL, long long qR, long long l, long long r,
             long long idx) {
    lazy(l, r, idx);
    if (l > qR || r < qL) return broken;
    if (qL <= l && r <= qR) return tr[idx];
    long long mid = (l + r) >> 1;
    return merge(query(qL, qR, l, mid, 2 * idx + 1),
                 query(qL, qR, mid + 1, r, 2 * idx + 2));
  }
};
vector<long long> G[MAXN];
void read() {
  cin >> n >> m;
  for (long long i = 1; i <= n; i++) cin >> a[i];
  for (long long i = 1; i <= n - 1; i++) {
    long long u, v;
    cin >> u >> v;
    G[u].push_back(v);
    G[v].push_back(u);
  }
}
long long dfs_time = 0;
long long st[MAXN], fi[MAXN];
void dfs(long long u, long long par) {
  st[u] = ++dfs_time;
  value[dfs_time] = a[u];
  long long v, sz = G[u].size();
  for (long long i = 0; i < sz; i++) {
    v = G[u][i];
    if (par != v) dfs(v, u);
  }
  fi[u] = dfs_time;
}
segment_tree t;
bitset<1000> mask_need;
bool seive[MAXN];
void solve() {
  for (long long i = 0; i < m; i++) helper_m[i] = 1;
  for (long long k = 2; k < m; k++)
    if (!seive[k]) {
      mask_need[k] = 1;
      for (long long j = 2 * k; j < m; j += k) seive[j] = true;
    }
  dfs(1, -1);
  t.init(1, dfs_time, 0);
  long long q;
  cin >> q;
  for (long long i = 0; i < q; i++) {
    long long type;
    cin >> type;
    if (type == 2) {
      long long u;
      cin >> u;
      cout << (t.query(st[u], fi[u], 1, dfs_time, 0).mask & mask_need).count()
           << '\n';
    } else {
      long long u, val;
      cin >> u >> val;
      t.update(st[u], fi[u], val, 1, dfs_time, 0);
    }
  }
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  read();
  solve();
  return 0;
}
