#include <bits/stdc++.h>

using namespace std;

int n,m,i,x,y,q,tp,v,Ans,j;
vector<int>g[100005];
bitset<1000>t[400005];
int tag[400005];
int ps[100005];
int sz[100005];
bitset<1000>X;
int a[100005];
int ord[100005];
bool vis[100005];
int P[2222];

void dfs(int x,int p)
{
    ord[++q]=x,ps[x]=q,sz[x]=1;
    for(int i=0;i<g[x].size();i++)
    {
        if(g[x][i]==p)continue;
        dfs(g[x][i],x);
        sz[x]+=sz[g[x][i]];
    }
}

void Build(int x,int l,int r)
{
    if(l==r)t[x].set(a[l]%m);
    else
    {
        int mid=(l+r)>>1;
        Build(x+x,l,mid);
        Build(x+x+1,mid+1,r);
        t[x]=t[x+x]|t[x+x+1];
    }
}
void Push(int x)
{
    if(tag[x]!=0)
    {
        tag[x]%=m;
        t[x]=((t[x]<<tag[x])&X)|(t[x]>>(m-tag[x]));
        tag[x+x]+=tag[x];
        tag[x+x+1]+=tag[x];
        tag[x]=0;
    }
}
void Rotate(int x,int l,int r,int ll,int rr,int shi)
{
    Push(x);
    if(l==ll&&r==rr)
    {
        tag[x]+=shi;
        Push(x);
    }
    else
    {
        int mid=(l+r)>>1;
        if(rr<=mid)Rotate(x+x,l,mid,ll,rr,shi);
        else if(ll>mid)Rotate(x+x+1,mid+1,r,ll,rr,shi);
        else
        {
            Rotate(x+x,l,mid,ll,mid,shi);
            Rotate(x+x+1,mid+1,r,mid+1,rr,shi);
        }
        t[x]=t[x+x]|t[x+x+1];
    }
    Push(x);
}
bitset<1000> Query(int x,int l,int r,int ll,int rr)
{
    Push(x);
    if(l==ll&&r==rr)return t[x];
    else
    {
        int mid=(l+r)>>1;
        if(rr<=mid)return Query(x+x,l,mid,ll,rr);
        else if(ll>mid)return Query(x+x+1,mid+1,r,ll,rr);
        else
        {
            bitset<1000>A=Query(x+x,l,mid,ll,mid);
            bitset<1000>B=Query(x+x+1,mid+1,r,mid+1,rr);
            return A|B;
        }
    }
    Push(x);
}

int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(int i=0;i<m;i++)X.set(i);
    for(int i=2;i<m;i++)if(!vis[i])
    {
        P[++P[0]]=i;
        for(int j=2*i;j<m;j+=i)vis[j]=1;
    }
    dfs(1,-1);
    Build(1,1,n);
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        scanf("%d",&tp);
        if(tp==1)
        {
            scanf("%d%d",&v,&x);
            Rotate(1,1,n,ps[v],ps[v]+sz[v]-1,x%m);
        }
        else
        {
            scanf("%d",&v);
            Ans=0;
            bitset<1000>A=Query(1,1,n,ps[v],ps[v]+sz[v]-1);
            for(int j=1;j<=P[0];j++)Ans+=A.test(P[j]);
            printf("%d\n",Ans);
        }
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int n,m,i,x,y,q,tp,v,Ans,j;
vector<int>g[1400005];
bitset<1000>t[1400005];
int tag[1400005];
int ps[1400005];
int sz[1400005];
bitset<1000>X;
int a[1400005];
int ord[1400005];
bool vis[1400005];
int P[2222];

void dfs(int x,int p)
{
    ord[++q]=x;
    ps[x]=q,sz[x]=1;
    for(int i=0;i<g[x].size();i++)
    {
        if(g[x][i]==p)continue;
        dfs(g[x][i],x);
        sz[x]+=sz[g[x][i]];
    }
}

void Build(int x,int l,int r)
{
    if(l==r)t[x].set(a[ord[l]]%m);
    else
    {
        int mid=(l+r)>>1;
        Build(x+x,l,mid);
        Build(x+x+1,mid+1,r);
        t[x]=t[x+x]|t[x+x+1];
    }
}

void Rot(int x,int sq)
{
    t[x]=(t[x]<<sq)|(t[x]>>(m-sq));
}

void Push(int x)
{
    tag[x]%=m;
    if(tag[x]!=0)
    {
        Rot(x+x,tag[x]);
        Rot(x+x+1,tag[x]);
        tag[x+x]+=tag[x];
        tag[x+x+1]+=tag[x];
        tag[x]=0;
    }
}
void Rotate(int x,int l,int r,int ll,int rr,int shi)
{
    Push(x),Push(x+x),Push(x+x+1);
    if(l==ll&&r==rr)
    {
        Rot(x,shi);
        tag[x]+=shi;
        tag[x]%=m;
        Push(x),Push(x+x),Push(x+x+1);
    }
    else
    {
        Push(x),Push(x+x),Push(x+x+1);
        int mid=(l+r)>>1;
        if(rr<=mid)Rotate(x+x,l,mid,ll,rr,shi);
        else if(ll>mid)Rotate(x+x+1,mid+1,r,ll,rr,shi);
        else
        {
            Rotate(x+x,l,mid,ll,mid,shi);
            Rotate(x+x+1,mid+1,r,mid+1,rr,shi);
        }
        Push(x),Push(x+x),Push(x+x+1);
        t[x]=t[x+x]|t[x+x+1];
        Push(x),Push(x+x),Push(x+x+1);
    }

    Push(x),Push(x+x),Push(x+x+1);
}
bitset<1000> Query(int x,int l,int r,int ll,int rr)
{

    Push(x),Push(x+x),Push(x+x+1);
    if(l==ll&&r==rr)return t[x];
    else
    {

    Push(x),Push(x+x),Push(x+x+1);
        int mid=(l+r)>>1;
        if(rr<=mid)return Query(x+x,l,mid,ll,rr);
        else if(ll>mid)return Query(x+x+1,mid+1,r,ll,rr);
        else
        {
            bitset<1000>A=Query(x+x,l,mid,ll,mid);
            bitset<1000>B=Query(x+x+1,mid+1,r,mid+1,rr);
            return A|B;
        }
    }

    Push(x),Push(x+x),Push(x+x+1);
}

int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(int i=2;i<m;i++)if(!vis[i])
    {
        P[++P[0]]=i;
        for(int j=2*i;j<m;j+=i)vis[j]=1;
    }
    dfs(1,-1);
    Build(1,1,n);
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        scanf("%d",&tp);
        if(tp==1)
        {
            scanf("%d%d",&v,&x);
            Rotate(1,1,n,ps[v],ps[v]+sz[v]-1,x%m);
        }
        else
        {
            scanf("%d",&v);
            Ans=0;
            bitset<1000>A=Query(1,1,n,ps[v],ps[v]+sz[v]-1);
            for(int j=1;j<=P[0];j++)Ans+=A.test(P[j]);
            printf("%d\n",Ans);
        }
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int n,m,i,x,y,q,tp,v,Ans,j;
vector<int>g[800005];
bitset<1000>t[800005];
int tag[800005];
int ps[800005];
int sz[800005];
bitset<1000>X;
int a[800005];
int ord[800005];
bool vis[800005];
int P[2222];

void dfs(int x,int p)
{
    ord[++q]=x;
    ps[x]=q,sz[x]=1;
    for(int i=0;i<g[x].size();i++)
    {
        if(g[x][i]==p)continue;
        dfs(g[x][i],x);
        sz[x]+=sz[g[x][i]];
    }
}

void Build(int x,int l,int r)
{
    if(l==r)t[x].set(a[ord[l]]%m);
    else
    {
        int mid=(l+r)>>1;
        Build(x+x,l,mid);
        Build(x+x+1,mid+1,r);
        t[x]=t[x+x]|t[x+x+1];
    }
}

void Rot(int x,int sq)
{
    t[x]=(t[x]<<sq)|(t[x]>>(m-sq));
}

void Push(int x)
{
    tag[x]%=m;
    if(tag[x]!=0)
    {
        Rot(x+x,tag[x]);
        Rot(x+x+1,tag[x]);
        tag[x+x]+=tag[x];
        tag[x+x+1]+=tag[x];
        tag[x]=0;
    }
}
void Rotate(int x,int l,int r,int ll,int rr,int shi)
{
    Push(x),Push(x+x),Push(x+x+1);
    if(l==ll&&r==rr)
    {
        Rot(x,shi);
        tag[x]+=shi;
        tag[x]%=m;
        Push(x),Push(x+x),Push(x+x+1);
    }
    else
    {
        Push(x),Push(x+x),Push(x+x+1);
        int mid=(l+r)>>1;
        if(rr<=mid)Rotate(x+x,l,mid,ll,rr,shi);
        else if(ll>mid)Rotate(x+x+1,mid+1,r,ll,rr,shi);
        else
        {
            Rotate(x+x,l,mid,ll,mid,shi);
            Rotate(x+x+1,mid+1,r,mid+1,rr,shi);
        }
        Push(x),Push(x+x),Push(x+x+1);
        t[x]=t[x+x]|t[x+x+1];
        Push(x),Push(x+x),Push(x+x+1);
    }

    Push(x),Push(x+x),Push(x+x+1);
}
bitset<1000> Query(int x,int l,int r,int ll,int rr)
{

    Push(x),Push(x+x),Push(x+x+1);
    if(l==ll&&r==rr)return t[x];
    else
    {

    Push(x),Push(x+x),Push(x+x+1);
        int mid=(l+r)>>1;
        if(rr<=mid)return Query(x+x,l,mid,ll,rr);
        else if(ll>mid)return Query(x+x+1,mid+1,r,ll,rr);
        else
        {
            bitset<1000>A=Query(x+x,l,mid,ll,mid);
            bitset<1000>B=Query(x+x+1,mid+1,r,mid+1,rr);
            return A|B;
        }
    }

    Push(x),Push(x+x),Push(x+x+1);
}

int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(int i=2;i<m;i++)if(!vis[i])
    {
        P[++P[0]]=i;
        for(int j=2*i;j<m;j+=i)vis[j]=1;
    }
    dfs(1,-1);
    Build(1,1,n);
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        scanf("%d",&tp);
        if(tp==1)
        {
            scanf("%d%d",&v,&x);
            Rotate(1,1,n,ps[v],ps[v]+sz[v]-1,x%m);
        }
        else
        {
            scanf("%d",&v);
            Ans=0;
            bitset<1000>A=Query(1,1,n,ps[v],ps[v]+sz[v]-1);
            for(int j=1;j<=P[0];j++)Ans+=A.test(P[j]);
            printf("%d\n",Ans);
        }
    }
    return 0;
}


#pragma comment(linker, "/STACK:512000000")
#define _CRT_SECURE_NO_WARNINGS
//#include "testlib.h"
#include <cstdio>
#include <cassert>
#include <algorithm>
#include <iostream>
#include <memory.h>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <bitset>
#include <deque>
#include <ctime>
#include <stack>
#include <queue>
#include <fstream>
#include <sstream>
//#include <unordered_map>
using namespace std;
//#define FILENAME ""
#define mp make_pair
#define all(a) a.begin(), a.end()
typedef long long li;
typedef long double ld;
void solve();
void precalc();
clock_t start;
//int timer = 1;

int testNumber = 1;

bool todo = true;

int main() {
#ifdef room111
	freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	//freopen(FILENAME".in", "r", stdin);
	//freopen(FILENAME ".out", "w", stdout);
#endif
	start = clock();
	int t = 1;
	cout.sync_with_stdio(0);
	cin.tie(0);
	precalc();
	cout.precision(10);
	cout << fixed;
	//cin >> t;
	int testNum = 1;
	while (t--) {
		//cerr << testNum << endl;
		//cout << "Case #" << testNum++ << ": ";
		solve();
		++testNumber;
		//++timer;
	}

#ifdef room111
	cerr << "\n\n" << (clock() - start) / 1.0 / CLOCKS_PER_SEC << "\n\n";
#endif

	return 0;
}

//BE CAREFUL: IS INT REALLY INT?

//#define int li

/*int pr[] = { 97, 2011 };
int mods[] = { 1000000007, 1000000009 };

const int C = 300500;
int powers[2][C];*/

//int MOD = 1000000007;

//int c[5010][5010];

template<typename T>
T binpow(T q, T w, T mod) {
	if (!w)
		return 1 % mod;
	if (w & 1)
		return q * 1LL * binpow(q, w - 1, mod) % mod;
	return binpow(q * 1LL * q % mod, w / 2, mod);
}

/*int curMod = 1000000009;

int fact[100500], revfact[100500];

int getC(int n, int k) {
int res = fact[n] * revfact[n - k] % curMod * revfact[k] % curMod;
return res;
}*/

/*const int C = 7000500;

int least_prime[C];*/

void precalc() {

	/*for (int i = 2; i < C; ++i) {
	if (!least_prime[i]) {
	least_prime[i] = i;
	for (li j = i * 1LL * i; j < C; j += i) {
	least_prime[j] = i;
	}
	}
	}*/

	/*fact[0] = revfact[0] = 1;
	for (int i = 1; i < 100500; ++i) {
	fact[i] = fact[i - 1] * i % curMod;
	revfact[i] = binpow(fact[i], curMod - 2, curMod);
	}*/

	/*for (int w = 0; w < 2; ++w) {
	powers[w][0] = 1;
	for (int j = 1; j < C; ++j) {
	powers[w][j] = (powers[w][j - 1] * 1LL * pr[w]) % mods[w];
	}
	}*/
	/*for (int i = 0; i < 5010; ++i) {
	c[i][i] = c[i][0] = 1;
	for (int j = 1; j < i; ++j) {
	c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % MOD;
	}
	}*/
}

template<typename T>
T gcd(T q, T w) {
	while (w) {
		q %= w;
		swap(q, w);
	}
	return q;
}
template<typename T>
T lcm(T q, T w) {
	return q / gcd(q, w) * w;
}

//#define int li

//const int mod = 1000000007;

bool is_prime(int cur) {
	for (int i = 2; i * i <= cur; ++i) {
		if (cur % i == 0) {
			return false;
		}
	}
	return true;
}

vector<int> primes;

vector<vector<int>> g;

vector<int> tin, tout;
vector<int> order;
int TIM = 0;

void dfs(int v, int p) {
	tin[v] = TIM++;
	order.push_back(v);
	for (int to : g[v]) {
		if (to == p) {
			continue;
		}
		dfs(to, v);
	}
	tout[v] = TIM;
}

typedef bitset<1024> Bitset;

int mod;

struct Node {
	Bitset cur_set;
	int pushed_val;
	Node(): pushed_val(0) {
	}
	Node(int val) {
		cur_set[val] = 1;
		pushed_val = 0;
	}
};

const int shift = 1 << 17;
vector<Node> tree(2 * shift);

void push(int v) {
	for (int h = 0; h < 2; ++h) {
		tree[2 * v + h].pushed_val = (tree[2 * v + h].pushed_val + tree[v].pushed_val) % mod;
	}
	tree[v].pushed_val = 0;
}

Bitset ideal;

Bitset normalize(const Bitset& cur, int shift) {
	Bitset res = ((cur << shift) | (cur >> (mod - shift)));
	res &= ideal;
	return res;
}

Node merge(Node& l, Node& r) {
	Node res;
	res.cur_set = (normalize(l.cur_set, l.pushed_val) | normalize(r.cur_set, r.pushed_val));
	return res;
}

Node rmq(int v, int tl, int tr, int l, int r) {
	if (r <= tl || tr <= l) {
		return Node();
	}
	if (l <= tl && tr <= r) {
		return tree[v];
	}
	push(v);
	int tm = (tl + tr) / 2;
	Node res = merge(rmq(2 * v, tl, tm, l, r), rmq(2 * v + 1, tm, tr, l, r));
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
	return res;
}

bitset<1024> get_set(int l, int r) {
	Node res = rmq(1, 0, shift, l, r);
	return normalize(res.cur_set, res.pushed_val);
}

void modify(int v, int tl, int tr, int l, int r, int val) {
	if (r <= tl || tr <= l) {
		return;
	}
	if (l <= tl && tr <= r) {
		tree[v].pushed_val = (tree[v].pushed_val + val) % mod;
		return;
	}
	push(v);
	int tm = (tl + tr) / 2;
	modify(2 * v, tl, tm, l, r, val);
	modify(2 * v + 1, tm, tr, l, r, val);
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
}

void update_shift(int l, int r, int val) {
	return modify(1, 0, shift, l, r, val);
}

void build(int v, int tl, int tr, const vector<int>& a) {
	if (tl + 1 == tr) {
		if (tl < a.size()) {
			tree[v] = Node(a[tl]);
		}
		else {
			tree[v] = Node();
		}
		return;
	}
	int tm = (tl + tr) / 2;
	build(2 * v, tl, tm, a);
	build(2 * v + 1, tm, tr, a);
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
}

void solve() {
	int n;
	cin >> n >> mod;
	for (int cur = 2; cur < mod; ++cur) {
		if (is_prime(cur)) {
			primes.push_back(cur);
		}
	}
	vector<int> a(n);
	for (int i = 0; i < n; ++i) {
		cin >> a[i];
		a[i] %= mod;
	}

	for (int i = 0; i < mod; ++i) {
		ideal[i] = 1;
	}

	g.resize(n);
	for (int i = 1; i < n; ++i) {
		int u, v;
		cin >> u >> v;
		--u; --v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	tin.resize(n);
	tout.resize(n);
	dfs(0, 0);

	build(1, 0, shift, a);

	int Q;
	cin >> Q;
	while (Q--) {
		int type, v;
		cin >> type >> v;
		--v;
		if (type == 2) {
			int ans = 0;
			Bitset res = get_set(tin[v], tout[v]);
			for (int p : primes) {
				if (res[p]) {
					++ans;
				}
			}
			cout << ans << '\n';
		}
		else {
			int x;
			cin >> x;
			x %= mod;
			update_shift(tin[v], tout[v], x);
		}
	}
}


#pragma comment(linker, "/STACK:512000000")
#define _CRT_SECURE_NO_WARNINGS
//#include "testlib.h"
#include <cstdio>
#include <cassert>
#include <algorithm>
#include <iostream>
#include <memory.h>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <bitset>
#include <deque>
#include <ctime>
#include <stack>
#include <queue>
#include <fstream>
#include <sstream>
//#include <unordered_map>
using namespace std;
//#define FILENAME ""
#define mp make_pair
#define all(a) a.begin(), a.end()
typedef long long li;
typedef long double ld;
void solve();
void precalc();
clock_t start;
//int timer = 1;

int testNumber = 1;

bool todo = true;

int main() {
#ifdef room111
	freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	//freopen(FILENAME".in", "r", stdin);
	//freopen(FILENAME ".out", "w", stdout);
#endif
	start = clock();
	int t = 1;
	cout.sync_with_stdio(0);
	cin.tie(0);
	precalc();
	cout.precision(10);
	cout << fixed;
	//cin >> t;
	int testNum = 1;
	while (t--) {
		//cerr << testNum << endl;
		//cout << "Case #" << testNum++ << ": ";
		solve();
		++testNumber;
		//++timer;
	}

#ifdef room111
	cerr << "\n\n" << (clock() - start) / 1.0 / CLOCKS_PER_SEC << "\n\n";
#endif

	return 0;
}

//BE CAREFUL: IS INT REALLY INT?

//#define int li

/*int pr[] = { 97, 2011 };
int mods[] = { 1000000007, 1000000009 };

const int C = 300500;
int powers[2][C];*/

//int MOD = 1000000007;

//int c[5010][5010];

template<typename T>
T binpow(T q, T w, T mod) {
	if (!w)
		return 1 % mod;
	if (w & 1)
		return q * 1LL * binpow(q, w - 1, mod) % mod;
	return binpow(q * 1LL * q % mod, w / 2, mod);
}

/*int curMod = 1000000009;

int fact[100500], revfact[100500];

int getC(int n, int k) {
int res = fact[n] * revfact[n - k] % curMod * revfact[k] % curMod;
return res;
}*/

/*const int C = 7000500;

int least_prime[C];*/

void precalc() {

	/*for (int i = 2; i < C; ++i) {
	if (!least_prime[i]) {
	least_prime[i] = i;
	for (li j = i * 1LL * i; j < C; j += i) {
	least_prime[j] = i;
	}
	}
	}*/

	/*fact[0] = revfact[0] = 1;
	for (int i = 1; i < 100500; ++i) {
	fact[i] = fact[i - 1] * i % curMod;
	revfact[i] = binpow(fact[i], curMod - 2, curMod);
	}*/

	/*for (int w = 0; w < 2; ++w) {
	powers[w][0] = 1;
	for (int j = 1; j < C; ++j) {
	powers[w][j] = (powers[w][j - 1] * 1LL * pr[w]) % mods[w];
	}
	}*/
	/*for (int i = 0; i < 5010; ++i) {
	c[i][i] = c[i][0] = 1;
	for (int j = 1; j < i; ++j) {
	c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % MOD;
	}
	}*/
}

template<typename T>
T gcd(T q, T w) {
	while (w) {
		q %= w;
		swap(q, w);
	}
	return q;
}
template<typename T>
T lcm(T q, T w) {
	return q / gcd(q, w) * w;
}

//#define int li

//const int mod = 1000000007;

bool is_prime(int cur) {
	for (int i = 2; i * i <= cur; ++i) {
		if (cur % i == 0) {
			return false;
		}
	}
	return true;
}

vector<int> primes;

vector<vector<int>> g;

vector<int> tin, tout;
vector<int> order;
int TIM = 0;

void dfs(int v, int p) {
	tin[v] = TIM++;
	order.push_back(v);
	for (int to : g[v]) {
		if (to == p) {
			continue;
		}
		dfs(to, v);
	}
	tout[v] = TIM;
}

typedef bitset<1024> Bitset;

int mod;

struct Node {
	Bitset cur_set;
	int pushed_val;
	Node(): pushed_val(0) {
	}
	Node(int val) {
		cur_set[val] = 1;
		pushed_val = 0;
	}
};

const int shift = 1 << 17;
vector<Node> tree(2 * shift);
Bitset ideal;

Bitset normalize(const Bitset& cur, int shift) {
	Bitset res = ((cur << shift) | (cur >> (mod - shift)));
	res &= ideal;
	return res;
}

void push(int v) {
	for (int h = 0; h < 2; ++h) {
		tree[2 * v + h].pushed_val = (tree[2 * v + h].pushed_val + tree[v].pushed_val) % mod;
		tree[2 * v + h].cur_set = normalize(tree[2 * v + h].cur_set, tree[v].pushed_val);
	}
	tree[v].pushed_val = 0;
}

Node merge(const Node& l, const Node& r) {
	Node res;
	res.cur_set = l.cur_set | r.cur_set;
	return res;
}

Node rmq(int v, int tl, int tr, int l, int r) {
	if (r <= tl || tr <= l) {
		return Node();
	}
	if (l <= tl && tr <= r) {
		return tree[v];
	}
	push(v);
	int tm = (tl + tr) / 2;
	Node res = merge(rmq(2 * v, tl, tm, l, r), rmq(2 * v + 1, tm, tr, l, r));
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
	return res;
}

Bitset get_set(int l, int r) {
	Node res = rmq(1, 0, shift, l, r);
	return normalize(res.cur_set, res.pushed_val);
}

void modify(int v, int tl, int tr, int l, int r, int val) {
	if (r <= tl || tr <= l) {
		return;
	}
	if (l <= tl && tr <= r) {
		tree[v].pushed_val = (tree[v].pushed_val + val) % mod;
		tree[v].cur_set = normalize(tree[v].cur_set, val);
		return;
	}
	push(v);
	int tm = (tl + tr) / 2;
	modify(2 * v, tl, tm, l, r, val);
	modify(2 * v + 1, tm, tr, l, r, val);
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
}

void update_shift(int l, int r, int val) {
	return modify(1, 0, shift, l, r, val);
}

void build(int v, int tl, int tr, const vector<int>& a, const vector<int>& order) {
	if (tl + 1 == tr) {
		if (tl < a.size()) {
			tree[v] = Node(a[order[tl]]);
		}
		else {
			tree[v] = Node();
		}
		return;
	}
	int tm = (tl + tr) / 2;
	build(2 * v, tl, tm, a, order);
	build(2 * v + 1, tm, tr, a, order);
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
}

void solve() {
	int n;
	cin >> n >> mod;
	for (int cur = 2; cur < mod; ++cur) {
		if (is_prime(cur)) {
			primes.push_back(cur);
		}
	}
	vector<int> a(n);
	for (int i = 0; i < n; ++i) {
		cin >> a[i];
		a[i] %= mod;
	}
	for (int i = 0; i < mod; ++i) {
		ideal[i] = 1;
	}
	g.resize(n);
	for (int i = 1; i < n; ++i) {
		int u, v;
		cin >> u >> v;
		--u; --v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	tin.resize(n);
	tout.resize(n);
	dfs(0, 0);

	build(1, 0, shift, a, order);

	int Q;
	cin >> Q;
	while (Q--) {
		int type, v;
		cin >> type >> v;
		--v;
		if (type == 2) {
			int ans = 0;
			Bitset res = get_set(tin[v], tout[v]);
			for (int p : primes) {
				if (res[p]) {
					++ans;
				}
			}
			cout << ans << '\n';
		}
		else {
			int x;
			cin >> x;
			x %= mod;
			update_shift(tin[v], tout[v], x);
		}
	}
}


#pragma comment(linker, "/STACK:512000000")
#define _CRT_SECURE_NO_WARNINGS
//#include "testlib.h"
#include <cstdio>
#include <cassert>
#include <algorithm>
#include <iostream>
#include <memory.h>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <bitset>
#include <deque>
#include <ctime>
#include <stack>
#include <queue>
#include <fstream>
#include <sstream>
//#include <unordered_map>
using namespace std;
//#define FILENAME ""
#define mp make_pair
#define all(a) a.begin(), a.end()
typedef long long li;
typedef long double ld;
void solve();
void precalc();
clock_t start;
//int timer = 1;

int testNumber = 1;

bool todo = true;

int main() {
#ifdef room111
	freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	//freopen(FILENAME".in", "r", stdin);
	//freopen(FILENAME ".out", "w", stdout);
#endif
	start = clock();
	int t = 1;
	cout.sync_with_stdio(0);
	cin.tie(0);
	precalc();
	cout.precision(10);
	cout << fixed;
	//cin >> t;
	int testNum = 1;
	while (t--) {
		//cerr << testNum << endl;
		//cout << "Case #" << testNum++ << ": ";
		solve();
		++testNumber;
		//++timer;
	}

#ifdef room111
	cerr << "\n\n" << (clock() - start) / 1.0 / CLOCKS_PER_SEC << "\n\n";
#endif

	return 0;
}

//BE CAREFUL: IS INT REALLY INT?

//#define int li

/*int pr[] = { 97, 2011 };
int mods[] = { 1000000007, 1000000009 };

const int C = 300500;
int powers[2][C];*/

//int MOD = 1000000007;

//int c[5010][5010];

template<typename T>
T binpow(T q, T w, T mod) {
	if (!w)
		return 1 % mod;
	if (w & 1)
		return q * 1LL * binpow(q, w - 1, mod) % mod;
	return binpow(q * 1LL * q % mod, w / 2, mod);
}

/*int curMod = 1000000009;

int fact[100500], revfact[100500];

int getC(int n, int k) {
int res = fact[n] * revfact[n - k] % curMod * revfact[k] % curMod;
return res;
}*/

/*const int C = 7000500;

int least_prime[C];*/

void precalc() {

	/*for (int i = 2; i < C; ++i) {
	if (!least_prime[i]) {
	least_prime[i] = i;
	for (li j = i * 1LL * i; j < C; j += i) {
	least_prime[j] = i;
	}
	}
	}*/

	/*fact[0] = revfact[0] = 1;
	for (int i = 1; i < 100500; ++i) {
	fact[i] = fact[i - 1] * i % curMod;
	revfact[i] = binpow(fact[i], curMod - 2, curMod);
	}*/

	/*for (int w = 0; w < 2; ++w) {
	powers[w][0] = 1;
	for (int j = 1; j < C; ++j) {
	powers[w][j] = (powers[w][j - 1] * 1LL * pr[w]) % mods[w];
	}
	}*/
	/*for (int i = 0; i < 5010; ++i) {
	c[i][i] = c[i][0] = 1;
	for (int j = 1; j < i; ++j) {
	c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % MOD;
	}
	}*/
}

template<typename T>
T gcd(T q, T w) {
	while (w) {
		q %= w;
		swap(q, w);
	}
	return q;
}
template<typename T>
T lcm(T q, T w) {
	return q / gcd(q, w) * w;
}

//#define int li

//const int mod = 1000000007;

bool is_prime(int cur) {
	for (int i = 2; i * i <= cur; ++i) {
		if (cur % i == 0) {
			return false;
		}
	}
	return true;
}

vector<int> primes;

vector<vector<int>> g;

vector<int> tin, tout;
vector<int> order;
int TIM = 0;

void dfs(int v, int p) {
	tin[v] = TIM++;
	order.push_back(v);
	for (int to : g[v]) {
		if (to == p) {
			continue;
		}
		dfs(to, v);
	}
	tout[v] = TIM;
}

typedef bitset<1024> Bitset;

int mod;

struct Node {
	Bitset cur_set;
	int pushed_val;
	Node(): pushed_val(0) {
	}
	Node(int val) {
		cur_set[val] = 1;
		pushed_val = 0;
	}
};

const int shift = 1 << 17;
vector<Node> tree(2 * shift);

Bitset ideal;

Bitset normalize(const Bitset& cur, int shift) {
	Bitset res = ((cur << shift) | (cur >> (mod - shift)));
	res &= ideal;
	return res;
}

void push(int v) {
	for (int h = 0; h < 2; ++h) {
		tree[2 * v + h].pushed_val = (tree[2 * v + h].pushed_val + tree[v].pushed_val) % mod;
		tree[2 * v + h].cur_set = normalize(tree[2 * v + h].cur_set, tree[v].pushed_val);
	}
	tree[v].pushed_val = 0;
}

Node merge(Node l, Node r) {
	Node res;
	res.cur_set = l.cur_set | r.cur_set;
	return res;
}

Node rmq(int v, int tl, int tr, int l, int r) {
	if (r <= tl || tr <= l) {
		return Node();
	}
	if (l <= tl && tr <= r) {
		return tree[v];
	}
	push(v);
	int tm = (tl + tr) / 2;
	Node res = merge(rmq(2 * v, tl, tm, l, r), rmq(2 * v + 1, tm, tr, l, r));
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
	return res;
}

bitset<1024> get_set(int l, int r) {
	Node res = rmq(1, 0, shift, l, r);
	return normalize(res.cur_set, res.pushed_val);
}

void modify(int v, int tl, int tr, int l, int r, int val) {
	if (r <= tl || tr <= l) {
		return;
	}
	if (l <= tl && tr <= r) {
		tree[v].pushed_val = (tree[v].pushed_val + val) % mod;
		tree[v].cur_set = normalize(tree[v].cur_set, val);
		return;
	}
	push(v);
	int tm = (tl + tr) / 2;
	modify(2 * v, tl, tm, l, r, val);
	modify(2 * v + 1, tm, tr, l, r, val);
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
}

void update_shift(int l, int r, int val) {
	return modify(1, 0, shift, l, r, val);
}

void build(int v, int tl, int tr, const vector<int>& a) {
	if (tl + 1 == tr) {
		if (tl < a.size()) {
			tree[v] = Node(a[tl]);
		}
		else {
			tree[v] = Node();
		}
		return;
	}
	int tm = (tl + tr) / 2;
	build(2 * v, tl, tm, a);
	build(2 * v + 1, tm, tr, a);
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
}

void solve() {
	int n;
	cin >> n >> mod;
	for (int cur = 2; cur < mod; ++cur) {
		if (is_prime(cur)) {
			primes.push_back(cur);
		}
	}
	vector<int> a(n);
	for (int i = 0; i < n; ++i) {
		cin >> a[i];
		a[i] %= mod;
	}

	for (int i = 0; i < mod; ++i) {
		ideal[i] = 1;
	}

	g.resize(n);
	for (int i = 1; i < n; ++i) {
		int u, v;
		cin >> u >> v;
		--u; --v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	tin.resize(n);
	tout.resize(n);
	dfs(0, 0);

	build(1, 0, shift, a);

	int Q;
	cin >> Q;
	while (Q--) {
		int type, v;
		cin >> type >> v;
		--v;
		if (type == 2) {
			int ans = 0;
			Bitset res = get_set(tin[v], tout[v]);
			for (int p : primes) {
				if (res[p]) {
					++ans;
				}
			}
			cout << ans << '\n';
		}
		else {
			int x;
			cin >> x;
			x %= mod;
			update_shift(tin[v], tout[v], x);
		}
	}
}


#pragma comment(linker, "/STACK:512000000")
#define _CRT_SECURE_NO_WARNINGS
//#include "testlib.h"
#include <cstdio>
#include <cassert>
#include <algorithm>
#include <iostream>
#include <memory.h>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <bitset>
#include <deque>
#include <ctime>
#include <stack>
#include <queue>
#include <fstream>
#include <sstream>
//#include <unordered_map>
using namespace std;
//#define FILENAME ""
#define mp make_pair
#define all(a) a.begin(), a.end()
typedef long long li;
typedef long double ld;
void solve();
void precalc();
clock_t start;
//int timer = 1;

int testNumber = 1;

bool todo = true;

int main() {
#ifdef room111
	freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	//freopen(FILENAME".in", "r", stdin);
	//freopen(FILENAME ".out", "w", stdout);
#endif
	start = clock();
	int t = 1;
	cout.sync_with_stdio(0);
	cin.tie(0);
	precalc();
	cout.precision(10);
	cout << fixed;
	//cin >> t;
	int testNum = 1;
	while (t--) {
		//cerr << testNum << endl;
		//cout << "Case #" << testNum++ << ": ";
		solve();
		++testNumber;
		//++timer;
	}

#ifdef room111
	cerr << "\n\n" << (clock() - start) / 1.0 / CLOCKS_PER_SEC << "\n\n";
#endif

	return 0;
}

//BE CAREFUL: IS INT REALLY INT?

//#define int li

/*int pr[] = { 97, 2011 };
int mods[] = { 1000000007, 1000000009 };

const int C = 300500;
int powers[2][C];*/

//int MOD = 1000000007;

//int c[5010][5010];

template<typename T>
T binpow(T q, T w, T mod) {
	if (!w)
		return 1 % mod;
	if (w & 1)
		return q * 1LL * binpow(q, w - 1, mod) % mod;
	return binpow(q * 1LL * q % mod, w / 2, mod);
}

/*int curMod = 1000000009;

int fact[100500], revfact[100500];

int getC(int n, int k) {
int res = fact[n] * revfact[n - k] % curMod * revfact[k] % curMod;
return res;
}*/

/*const int C = 7000500;

int least_prime[C];*/

void precalc() {

	/*for (int i = 2; i < C; ++i) {
	if (!least_prime[i]) {
	least_prime[i] = i;
	for (li j = i * 1LL * i; j < C; j += i) {
	least_prime[j] = i;
	}
	}
	}*/

	/*fact[0] = revfact[0] = 1;
	for (int i = 1; i < 100500; ++i) {
	fact[i] = fact[i - 1] * i % curMod;
	revfact[i] = binpow(fact[i], curMod - 2, curMod);
	}*/

	/*for (int w = 0; w < 2; ++w) {
	powers[w][0] = 1;
	for (int j = 1; j < C; ++j) {
	powers[w][j] = (powers[w][j - 1] * 1LL * pr[w]) % mods[w];
	}
	}*/
	/*for (int i = 0; i < 5010; ++i) {
	c[i][i] = c[i][0] = 1;
	for (int j = 1; j < i; ++j) {
	c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % MOD;
	}
	}*/
}

template<typename T>
T gcd(T q, T w) {
	while (w) {
		q %= w;
		swap(q, w);
	}
	return q;
}
template<typename T>
T lcm(T q, T w) {
	return q / gcd(q, w) * w;
}

//#define int li

//const int mod = 1000000007;

bool is_prime(int cur) {
	for (int i = 2; i * i <= cur; ++i) {
		if (cur % i == 0) {
			return false;
		}
	}
	return true;
}

vector<int> primes;

vector<vector<int>> g;

vector<int> tin, tout;
vector<int> order;
int TIM = 0;

void dfs(int v, int p) {
	tin[v] = TIM++;
	order.push_back(v);
	for (int to : g[v]) {
		if (to == p) {
			continue;
		}
		dfs(to, v);
	}
	tout[v] = TIM + 1;
}

typedef bitset<1024> Bitset;

int mod;

struct Node {
	Bitset cur_set;
	int pushed_val;
	Node(): pushed_val(0) {
	}
	Node(int val) {
		cur_set[val] = 1;
		pushed_val = 0;
	}
};

const int shift = 1 << 17;
vector<Node> tree(2 * shift);
Bitset ideal;

Bitset normalize(const Bitset& cur, int shift) {
	Bitset res = ((cur << shift) | (cur >> (mod - shift)));
	res &= ideal;
	return res;
}

void push(int v) {
	for (int h = 0; h < 2; ++h) {
		tree[2 * v + h].pushed_val = (tree[2 * v + h].pushed_val + tree[v].pushed_val) % mod;
		tree[2 * v + h].cur_set = normalize(tree[2 * v + h].cur_set, tree[v].pushed_val);
	}
	tree[v].pushed_val = 0;
}

Node merge(const Node& l, const Node& r) {
	Node res;
	res.cur_set = l.cur_set | r.cur_set;
	return res;
}

Node rmq(int v, int tl, int tr, int l, int r) {
	if (r <= tl || tr <= l) {
		return Node();
	}
	if (l <= tl && tr <= r) {
		return tree[v];
	}
	push(v);
	int tm = (tl + tr) / 2;
	Node res = merge(rmq(2 * v, tl, tm, l, r), rmq(2 * v + 1, tm, tr, l, r));
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
	return res;
}

bitset<1024> get_set(int l, int r) {
	Node res = rmq(1, 0, shift, l, r);
	return normalize(res.cur_set, res.pushed_val);
}

void modify(int v, int tl, int tr, int l, int r, int val) {
	if (r <= tl || tr <= l) {
		return;
	}
	if (l <= tl && tr <= r) {
		tree[v].pushed_val = (tree[v].pushed_val + val) % mod;
		tree[v].cur_set = normalize(tree[v].cur_set, val);
		return;
	}
	push(v);
	int tm = (tl + tr) / 2;
	modify(2 * v, tl, tm, l, r, val);
	modify(2 * v + 1, tm, tr, l, r, val);
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
}

void update_shift(int l, int r, int val) {
	return modify(1, 0, shift, l, r, val);
}

void build(int v, int tl, int tr, const vector<int>& a) {
	if (tl + 1 == tr) {
		if (tl < a.size()) {
			tree[v] = Node(a[tl]);
		}
		else {
			tree[v] = Node();
		}
		return;
	}
	int tm = (tl + tr) / 2;
	build(2 * v, tl, tm, a);
	build(2 * v + 1, tm, tr, a);
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
}

void solve() {
	int n;
	cin >> n >> mod;
	for (int cur = 2; cur < mod; ++cur) {
		if (is_prime(cur)) {
			primes.push_back(cur);
		}
	}
	vector<int> a(n);
	for (int i = 0; i < n; ++i) {
		cin >> a[i];
		a[i] %= mod;
	}
	for (int i = 0; i < mod; ++i) {
		ideal[i] = 1;
	}
	g.resize(n);
	for (int i = 1; i < n; ++i) {
		int u, v;
		cin >> u >> v;
		--u; --v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	tin.resize(n);
	tout.resize(n);
	dfs(0, 0);

	build(1, 0, shift, a);

	int Q;
	cin >> Q;
	while (Q--) {
		int type, v;
		cin >> type >> v;
		--v;
		if (type == 2) {
			int ans = 0;
			Bitset res = get_set(tin[v], tout[v]);
			for (int p : primes) {
				if (res[p]) {
					++ans;
				}
			}
			cout << ans << '\n';
		}
		else {
			int x;
			cin >> x;
			x %= mod;
			update_shift(tin[v], tout[v], x);
		}
	}
}


#pragma comment(linker, "/STACK:512000000")
#define _CRT_SECURE_NO_WARNINGS
//#include "testlib.h"
#include <cstdio>
#include <cassert>
#include <algorithm>
#include <iostream>
#include <memory.h>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <bitset>
#include <deque>
#include <ctime>
#include <stack>
#include <queue>
#include <fstream>
#include <sstream>
//#include <unordered_map>
using namespace std;
//#define FILENAME ""
#define mp make_pair
#define all(a) a.begin(), a.end()
typedef long long li;
typedef long double ld;
void solve();
void precalc();
clock_t start;
//int timer = 1;

int testNumber = 1;

bool todo = true;

int main() {
#ifdef room111
	freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	//freopen(FILENAME".in", "r", stdin);
	//freopen(FILENAME ".out", "w", stdout);
#endif
	start = clock();
	int t = 1;
	cout.sync_with_stdio(0);
	cin.tie(0);
	precalc();
	cout.precision(10);
	cout << fixed;
	//cin >> t;
	int testNum = 1;
	while (t--) {
		//cerr << testNum << endl;
		//cout << "Case #" << testNum++ << ": ";
		solve();
		++testNumber;
		//++timer;
	}

#ifdef room111
	cerr << "\n\n" << (clock() - start) / 1.0 / CLOCKS_PER_SEC << "\n\n";
#endif

	return 0;
}

//BE CAREFUL: IS INT REALLY INT?

//#define int li

/*int pr[] = { 97, 2011 };
int mods[] = { 1000000007, 1000000009 };

const int C = 300500;
int powers[2][C];*/

//int MOD = 1000000007;

//int c[5010][5010];

template<typename T>
T binpow(T q, T w, T mod) {
	if (!w)
		return 1 % mod;
	if (w & 1)
		return q * 1LL * binpow(q, w - 1, mod) % mod;
	return binpow(q * 1LL * q % mod, w / 2, mod);
}

/*int curMod = 1000000009;

int fact[100500], revfact[100500];

int getC(int n, int k) {
int res = fact[n] * revfact[n - k] % curMod * revfact[k] % curMod;
return res;
}*/

/*const int C = 7000500;

int least_prime[C];*/

void precalc() {

	/*for (int i = 2; i < C; ++i) {
	if (!least_prime[i]) {
	least_prime[i] = i;
	for (li j = i * 1LL * i; j < C; j += i) {
	least_prime[j] = i;
	}
	}
	}*/

	/*fact[0] = revfact[0] = 1;
	for (int i = 1; i < 100500; ++i) {
	fact[i] = fact[i - 1] * i % curMod;
	revfact[i] = binpow(fact[i], curMod - 2, curMod);
	}*/

	/*for (int w = 0; w < 2; ++w) {
	powers[w][0] = 1;
	for (int j = 1; j < C; ++j) {
	powers[w][j] = (powers[w][j - 1] * 1LL * pr[w]) % mods[w];
	}
	}*/
	/*for (int i = 0; i < 5010; ++i) {
	c[i][i] = c[i][0] = 1;
	for (int j = 1; j < i; ++j) {
	c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % MOD;
	}
	}*/
}

template<typename T>
T gcd(T q, T w) {
	while (w) {
		q %= w;
		swap(q, w);
	}
	return q;
}
template<typename T>
T lcm(T q, T w) {
	return q / gcd(q, w) * w;
}

//#define int li

//const int mod = 1000000007;

bool is_prime(int cur) {
	for (int i = 2; i * i <= cur; ++i) {
		if (cur % i == 0) {
			return false;
		}
	}
	return true;
}

vector<int> primes;

vector<vector<int>> g;

vector<int> tin, tout;
vector<int> order;
int TIM = 0;

void dfs(int v, int p) {
	tin[v] = TIM++;
	order.push_back(v);
	for (int to : g[v]) {
		if (to == p) {
			continue;
		}
		dfs(to, v);
	}
	tout[v] = TIM;
}

typedef bitset<1024> Bitset;

int mod;

struct Node {
	Bitset cur_set;
	int pushed_val;
	Node(): pushed_val(0) {
	}
	Node(int val) {
		cur_set[val] = 1;
		pushed_val = 0;
	}
};

const int shift = 1 << 17;
vector<Node> tree(2 * shift);

void push(int v) {
	for (int h = 0; h < 2; ++h) {
		tree[2 * v + h].pushed_val = (tree[2 * v + h].pushed_val + tree[v].pushed_val) % mod;
	}
	tree[v].pushed_val = 0;
}

Bitset ideal;

Bitset normalize(const Bitset& cur, int shift) {
	Bitset res = ((cur << shift) | (cur >> (mod - shift)));
	res &= ideal;
	return res;
}

Node merge(Node l, Node r) {
	Node res;
	res.cur_set = (normalize(l.cur_set, l.pushed_val) | normalize(r.cur_set, r.pushed_val));
	return res;
}

Node rmq(int v, int tl, int tr, int l, int r) {
	if (r <= tl || tr <= l) {
		return Node();
	}
	if (l <= tl && tr <= r) {
		return tree[v];
	}
	push(v);
	int tm = (tl + tr) / 2;
	Node res = merge(rmq(2 * v, tl, tm, l, r), rmq(2 * v + 1, tm, tr, l, r));
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
	return res;
}

bitset<1024> get_set(int l, int r) {
	Node res = rmq(1, 0, shift, l, r);
	return normalize(res.cur_set, res.pushed_val);
}

void modify(int v, int tl, int tr, int l, int r, int val) {
	if (r <= tl || tr <= l) {
		return;
	}
	if (l <= tl && tr <= r) {
		tree[v].pushed_val = (tree[v].pushed_val + val) % mod;
		return;
	}
	push(v);
	int tm = (tl + tr) / 2;
	modify(2 * v, tl, tm, l, r, val);
	modify(2 * v + 1, tm, tr, l, r, val);
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
}

void update_shift(int l, int r, int val) {
	return modify(1, 0, shift, l, r, val);
}

void build(int v, int tl, int tr, const vector<int>& a) {
	if (tl + 1 == tr) {
		if (tl < a.size()) {
			tree[v] = Node(a[tl]);
		}
		else {
			tree[v] = Node();
		}
		return;
	}
	int tm = (tl + tr) / 2;
	build(2 * v, tl, tm, a);
	build(2 * v + 1, tm, tr, a);
	tree[v] = merge(tree[2 * v], tree[2 * v + 1]);
}

void solve() {
	int n;
	cin >> n >> mod;
	for (int cur = 2; cur < mod; ++cur) {
		if (is_prime(cur)) {
			primes.push_back(cur);
		}
	}
	vector<int> a(n);
	for (int i = 0; i < n; ++i) {
		cin >> a[i];
		a[i] %= mod;
	}

	for (int i = 0; i < mod; ++i) {
		ideal[i] = 1;
	}

	g.resize(n);
	for (int i = 1; i < n; ++i) {
		int u, v;
		cin >> u >> v;
		--u; --v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	tin.resize(n);
	tout.resize(n);
	dfs(0, 0);

	build(1, 0, shift, a);

	int Q;
	cin >> Q;
	while (Q--) {
		int type, v;
		cin >> type >> v;
		--v;
		if (type == 2) {
			int ans = 0;
			Bitset res = get_set(tin[v], tout[v]);
			for (int p : primes) {
				if (res[p]) {
					++ans;
				}
			}
			cout << ans << '\n';
		}
		else {
			int x;
			cin >> x;
			x %= mod;
			update_shift(tin[v], tout[v], x);
		}
	}
}


#include <bits/stdc++.h>

using namespace std;
const int BitSize = 1000;
const int maxn = 1e5 + 500;
int head[maxn] , tot , Q , n , m , vis[1500] , in[maxn] , out[maxn] , dfs_clock , p[maxn];
struct edge{
	int v , nxt;
}e[maxn << 1];

bitset < BitSize > prime;

bitset < BitSize > Left_shift( const bitset < BitSize > & a , int b ){
	return ( a << b ) | ( a >> ( BitSize - b ) );
}

void init_prime(){
	for(int i = 2 ; i < m ; ++ i)
		if(!vis[i]){
			prime[i] = 1;
			for(int j = i * 2 ; j < m ; j += i) vis[j] = 1;
		}
}

struct Segmenttree
{
	typedef int SgTreeDataType;
	struct treenode
	{
	  int L , R  , lazy ;
	  bitset < BitSize > val;
	  void updata(SgTreeDataType v){
	  	val = Left_shift( val , v );
	  	lazy += v;
	  	if( lazy >= BitSize ) lazy %= BitSize;
	  }
	};

	treenode tree[maxn * 4];

	inline void push_down(int o){
		int lson = o << 1 , rson = o << 1 | 1;
		if(tree[o].lazy == 0) return;
		tree[lson].updata(tree[o].lazy) ; tree[rson].updata(tree[o].lazy);
		tree[o].lazy = 0;
	}

	inline void push_up(int o){
		int lson = o << 1 , rson = o << 1 | 1;
		tree[o].val = tree[lson].val | tree[rson].val;
	}

	void build(int L , int R , int o){
		tree[o].L = L , tree[o].R = R;tree[o].val[0]=1;tree[o].lazy=0;
		if (R > L){
			int mid = (L+R) >> 1;
			build(L,mid,o<<1);
			build(mid+1,R,o<<1|1);
		}
	}

	void updata(int QL,int QR,SgTreeDataType v,int o){
		int L = tree[o].L , R = tree[o].R;
		if (QL <= L && R <= QR) tree[o].updata(v);
		else{
			push_down(o);
			int mid = (L+R)>>1;
			if (QL <= mid) updata(QL,QR,v,o<<1);
			if (QR >  mid) updata(QL,QR,v,o<<1|1);
			push_up(o);
		}
	}

	bitset < BitSize > query(int QL,int QR,int o){
		int L = tree[o].L , R = tree[o].R;
		if (QL <= L && R <= QR) return tree[o].val;
		else{
			push_down(o);
			int mid = (L+R)>>1;
			bitset < BitSize > res ;
			if (QL <= mid) res |= query(QL,QR,o<<1);
			if (QR > mid) res |= query(QL,QR,o<<1|1);
			push_up(o);
			return res;
		}
	}
}Sgtree;

void link(int u , int v){
	e[tot].v=v,e[tot].nxt=head[u],head[u]=tot++;
}

void dfs(int u , int fa){
	in[u] = ++ dfs_clock;
	for(int i = head[u] ; ~i ; i = e[i].nxt){
		int v = e[i].v;
		if( v == fa ) continue;
		dfs( v , u );
	}
	out[u] = dfs_clock;
}

int main(int argc,char *argv[]){
	memset( head , -1 , sizeof( head ) );
	scanf("%d%d",&n,&m);
	for(int i = 1 ; i <= n ; ++ i) scanf("%d" , p + i );
	init_prime();
	for(int i = 1 ; i < n ; ++ i){
		int u , v ;
		scanf("%d%d" ,&u,&v);
		link( u , v ) ; link( v , u );
	}
	dfs( 1 , 0 );
	Sgtree.build( 1 , n , 1 );
	for(int i = 1 ; i <= n ; ++ i) Sgtree.updata( in[i] , in[i] , p[i] % BitSize , 1 );
	scanf("%d",&Q);
	while(Q--){
		int x , y , z;
		scanf("%d%d",&x,&y);
		if( x == 1 ){
			scanf("%d",&z);
			z %= BitSize;
			Sgtree.updata( in[y] , out[y] , z , 1 );
		}else printf("%d\n" , (Sgtree.query( in[y] , out[y] , 1 )&prime).count() );
	}
	return 0;
}


#include <bits/stdc++.h>

using namespace std;
const int BitSize = 1000;
const int maxn = 1e5 + 500;
int head[maxn] , tot , Q , n , m , vis[1500] , in[maxn] , out[maxn] , dfs_clock , p[maxn];
struct edge{
	int v , nxt;
}e[maxn << 1];

bitset < BitSize > prime;

bitset < BitSize > Left_shift( const bitset < BitSize > & a , int b ){
	return a << b | ( a >> ( BitSize - b ) );
}

void init_prime(){
	for(int i = 2 ; i < m ; ++ i)
		if(!vis[i]){
			prime.set( i );
			for(int j = i * 2 ; j < m ; j += i) vis[j] = 1;
		}
}

struct Segmenttree
{
	typedef int SgTreeDataType;
	struct treenode
	{
	  int L , R  , lazy ;
	  bitset < BitSize > val;
	  void updata(SgTreeDataType v){
	  	val = Left_shift( val , v );
	  	lazy += v;
	  	if( lazy >= BitSize ) lazy -= BitSize;
	  }
	};

	treenode tree[maxn * 4];

	inline void push_down(int o){
		int lson = o << 1 , rson = o << 1 | 1;
		if(tree[o].lazy == 0) return;
		tree[lson].updata(tree[o].lazy) ; tree[rson].updata(tree[o].lazy);
		tree[o].lazy = 0;
	}

	inline void push_up(int o){
		int lson = o << 1 , rson = o << 1 | 1;
		tree[o].val = tree[lson].val | tree[rson].val;
	}

	void build(int L , int R , int o){
		tree[o].L = L , tree[o].R = R,tree[o].val.reset();tree[o].val[0]=1;tree[o].lazy=0;
		if (R > L){
			int mid = (L+R) >> 1;
			build(L,mid,o<<1);
			build(mid+1,R,o<<1|1);
		}
	}

	void updata(int QL,int QR,SgTreeDataType v,int o){
		int L = tree[o].L , R = tree[o].R;
		if (QL <= L && R <= QR) tree[o].updata(v);
		else{
			push_down(o);
			int mid = (L+R)>>1;
			if (QL <= mid) updata(QL,QR,v,o<<1);
			if (QR >  mid) updata(QL,QR,v,o<<1|1);
			push_up(o);
		}
	}

	SgTreeDataType query(int QL,int QR,int o){
		int L = tree[o].L , R = tree[o].R;
		if (QL <= L && R <= QR) return (prime&tree[o].val).count();
		else{
			push_down(o);
			int mid = (L+R)>>1;
			SgTreeDataType res = 0;
			if (QL <= mid) res += query(QL,QR,o<<1);
			if (QR > mid) res += query(QL,QR,o<<1|1);
			push_up(o);
			return res;
		}
	}
}Sgtree;

void link(int u , int v){
	e[tot].v=v,e[tot].nxt=head[u],head[u]=tot++;
}

void dfs(int u , int fa){
	in[u] = ++ dfs_clock;
	for(int i = head[u] ; ~i ; i = e[i].nxt){
		int v = e[i].v;
		if( v == fa ) continue;
		dfs( v , u );
	}
	out[u] = dfs_clock;
}

int main(int argc,char *argv[]){
	memset( head , -1 , sizeof( head ) );
	scanf("%d%d",&n,&m);
	for(int i = 1 ; i <= n ; ++ i) scanf("%d" , p + i );
	init_prime();
	for(int i = 1 ; i < n ; ++ i){
		int u , v ;
		scanf("%d%d" ,&u,&v);
		link( u , v ) ; link( v , u );
	}
	dfs( 1 , 0 );
	Sgtree.build( 1 , n , 1 );
	for(int i = 1 ; i <= n ; ++ i) Sgtree.updata( in[i] , in[i] , p[i] % BitSize , 1 );
	scanf("%d",&Q);
	while(Q--){
		int x , y , z;
		scanf("%d%d",&x,&y);
		if( x == 1 ){
			scanf("%d",&z);
			z %= BitSize;
			Sgtree.updata( in[y] , out[y] , z , 1 );
		}else printf("%d\n" , Sgtree.query( in[y] , out[y] , 1 ));
	}
	return 0;
}


#include <bits/stdc++.h>

using namespace std;
const int BitSize = 1000;
const int maxn = 1e5 + 500;
int head[maxn] , tot , Q , n , m , vis[1500] , in[maxn] , out[maxn] , dfs_clock , p[maxn];
struct edge{
	int v , nxt;
}e[maxn << 1];

bitset < BitSize > prime;

bitset < BitSize > Left_shift( const bitset < BitSize > & a , int b ){
	return ( a << b ) | ( a >> ( BitSize - b ) );
}

void init_prime(){
	for(int i = 2 ; i < m ; ++ i)
		if(!vis[i]){
			prime[i] = 1;
			for(int j = i * 2 ; j < m ; j += i) vis[j] = 1;
		}
}

struct Segmenttree
{
	typedef int SgTreeDataType;
	struct treenode
	{
	  int L , R  , lazy ;
	  bitset < BitSize > val;
	  void updata(SgTreeDataType v){
	  	val = Left_shift( val , v );
	  	lazy += v;
	  	if( lazy >= BitSize ) lazy %= BitSize;
	  }
	};

	treenode tree[maxn * 4];

	inline void push_down(int o){
		int lson = o << 1 , rson = o << 1 | 1;
		if(tree[o].lazy == 0) return;
		tree[lson].updata(tree[o].lazy) ; tree[rson].updata(tree[o].lazy);
		tree[o].lazy = 0;
	}

	inline void push_up(int o){
		int lson = o << 1 , rson = o << 1 | 1;
		tree[o].val = tree[lson].val | tree[rson].val;
	}

	void build(int L , int R , int o){
		tree[o].L = L , tree[o].R = R;tree[o].val[0]=1;tree[o].lazy=0;
		if (R > L){
			int mid = (L+R) >> 1;
			build(L,mid,o<<1);
			build(mid+1,R,o<<1|1);
		}
	}

	void updata(int QL,int QR,SgTreeDataType v,int o){
		int L = tree[o].L , R = tree[o].R;
		if (QL <= L && R <= QR) tree[o].updata(v);
		else{
			push_down(o);
			int mid = (L+R)>>1;
			if (QL <= mid) updata(QL,QR,v,o<<1);
			if (QR >  mid) updata(QL,QR,v,o<<1|1);
			push_up(o);
		}
	}

	bitset < BitSize > query(int QL,int QR,int o){
		int L = tree[o].L , R = tree[o].R;
		if (QL <= L && R <= QR) return tree[o].val;
		else{
			push_down(o);
			int mid = (L+R)>>1;
			bitset < BitSize > res ;
			if (QL <= mid) res |= query(QL,QR,o<<1);
			if (QR > mid) res |= query(QL,QR,o<<1|1);
			push_up(o);
			return res;
		}
	}
}Sgtree;

void link(int u , int v){
	e[tot].v=v,e[tot].nxt=head[u],head[u]=tot++;
}

void dfs(int u , int fa){
	in[u] = ++ dfs_clock;
	for(int i = head[u] ; ~i ; i = e[i].nxt){
		int v = e[i].v;
		if( v == fa ) continue;
		dfs( v , u );
	}
	out[u] = dfs_clock;
}

int main(int argc,char *argv[]){
	memset( head , -1 , sizeof( head ) );
	scanf("%d%d",&n,&m);
	for(int i = 1 ; i <= n ; ++ i) scanf("%d" , p + i );
	init_prime();
	for(int i = 1 ; i < n ; ++ i){
		int u , v ;
		scanf("%d%d" ,&u,&v);
		link( u , v ) ; link( v , u );
	}
	dfs( 1 , 0 );
	Sgtree.build( 1 , n , 1 );
	for(int i = 1 ; i <= n ; ++ i) Sgtree.updata( in[i] , in[i] , p[i] % BitSize , 1 );
	scanf("%d",&Q);
	while(Q--){
		int x , y , z;
		scanf("%d%d",&x,&y);
		if( x == 1 ){
			scanf("%d",&z);
			z %= BitSize;
			Sgtree.updata( in[y] , out[y] , z , 1 );
		}else{
			bitset < BitSize > ans = Sgtree.query( in[y] , out[y] , 1 );
			ans &= prime;
			printf("%d\n" , ans.count() );
		}
	}
	return 0;
}


#include <bits/stdc++.h>

using namespace std;
const int BitSize = 1000;
const int maxn = 1e5 + 500;
int head[maxn] , tot , Q , n , m , vis[1500] , in[maxn] , out[maxn] , dfs_clock , p[maxn];
struct edge{
	int v , nxt;
}e[maxn << 2];

bitset < BitSize > prime;

bitset < BitSize > Left_shift( const bitset < BitSize > & a , int b ){
	assert( b <= BitSize );
	return ( a << b ) | ( a >> ( BitSize - b ) );
}

void init_prime(){
	for(int i = 2 ; i < m ; ++ i)
		if(!vis[i]){
			prime[i] = 1;
			for(int j = i * 2 ; j < m ; j += i) vis[j] = 1;
		}
}

struct Segmenttree
{
	typedef int SgTreeDataType;
	struct treenode
	{
	  int L , R  , lazy ;
	  bitset < BitSize > val;
	  void updata(SgTreeDataType v){
	  	val = Left_shift( val , v );
	  	lazy += v;
	  	if( lazy >= BitSize ) lazy %= BitSize;
	  }
	};

	treenode tree[maxn * 4];

	inline void push_down(int o){
		int lson = o << 1 , rson = o << 1 | 1;
		if(tree[o].lazy == 0) return;
		tree[lson].updata(tree[o].lazy) ; tree[rson].updata(tree[o].lazy);
		tree[o].lazy = 0;
	}

	inline void push_up(int o){
		int lson = o << 1 , rson = o << 1 | 1;
		tree[o].val = tree[lson].val | tree[rson].val;
	}

	void build(int L , int R , int o){
		tree[o].L = L , tree[o].R = R;tree[o].val[0]=1;tree[o].lazy=0;
		if (R > L){
			int mid = (L+R) >> 1;
			build(L,mid,o<<1);
			build(mid+1,R,o<<1|1);
		}
	}

	void updata(int QL,int QR,SgTreeDataType v,int o){
		int L = tree[o].L , R = tree[o].R;
		if (QL <= L && R <= QR) tree[o].updata(v);
		else{
			push_down(o);
			int mid = (L+R)>>1;
			if (QL <= mid) updata(QL,QR,v,o<<1);
			if (QR >  mid) updata(QL,QR,v,o<<1|1);
			push_up(o);
		}
	}

	bitset < BitSize > query(int QL,int QR,int o){
		int L = tree[o].L , R = tree[o].R;
		if (QL <= L && R <= QR) return tree[o].val;
		else{
			push_down(o);
			int mid = (L+R)>>1;
			bitset < BitSize > res ; res.reset();
			if (QL <= mid) res |= query(QL,QR,o<<1);
			if (QR > mid) res |= query(QL,QR,o<<1|1);
			push_up(o);
			return res;
		}
	}
}Sgtree;

void link(int u , int v){
	e[tot].v=v,e[tot].nxt=head[u],head[u]=tot++;
}

void dfs(int u , int fa){
	in[u] = ++ dfs_clock;
	for(int i = head[u] ; ~i ; i = e[i].nxt){
		int v = e[i].v;
		if( v == fa ) continue;
		dfs( v , u );
	}
	out[u] = dfs_clock;
}

int main(int argc,char *argv[]){
	memset( head , -1 , sizeof( head ) );
	scanf("%d%d",&n,&m);
	for(int i = 1 ; i <= n ; ++ i) scanf("%d" , p + i );
	init_prime();
	for(int i = 1 ; i < n ; ++ i){
		int u , v ;
		scanf("%d%d" ,&u,&v);
		link( u , v ) ; link( v , u );
	}
	dfs( 1 , 0 );
	Sgtree.build( 1 , dfs_clock , 1 );
	for(int i = 1 ; i <= n ; ++ i) Sgtree.updata( in[i] , in[i] , p[i] % BitSize , 1 );
	scanf("%d",&Q);
	while(Q--){
		int x , y , z;
		scanf("%d%d",&x,&y);
		if( x == 1 ){
			scanf("%d",&z);
			z %= BitSize;
			Sgtree.updata( in[y] , out[y] , z , 1 );
		}else{
			bitset < BitSize > ans = Sgtree.query( in[y] , out[y] , 1 );
			ans &= prime;
			printf("%d\n" , ans.count() );
		}
	}
	return 0;
}


#include <bits/stdc++.h>

using namespace std;
const int BitSize = 1000;
const int maxn = 1e5 + 500;
int head[maxn] , tot , Q , n , m , vis[1500] , in[maxn] , out[maxn] , dfs_clock , p[maxn];
struct edge{
	int v , nxt;
}e[maxn << 2];

bitset < BitSize > prime;

void init_prime(){
	for(int i = 2 ; i < m ; ++ i)
		if(!vis[i]){
			prime[i] = 1;
			for(int j = i * 2 ; j < m ; j += i) vis[j] = 1;
		}
}

struct Segmenttree
{
	typedef int SgTreeDataType;
	struct treenode
	{
	  int L , R  , lazy ;
	  bitset < BitSize > val;
	  void updata(SgTreeDataType v){
	  	val = (val << v) | (val >> ( m - v ) );
	  	lazy += v;
	  	if( lazy >= m ) lazy %= m;
	  }
	};

	treenode tree[maxn * 4];

	inline void push_down(int o){
		int lson = o << 1 , rson = o << 1 | 1;
		if(tree[o].lazy == 0) return;
		tree[lson].updata(tree[o].lazy) ; tree[rson].updata(tree[o].lazy);
		tree[o].lazy = 0;
	}

	inline void push_up(int o){
		int lson = o << 1 , rson = o << 1 | 1;
		tree[o].val = tree[lson].val | tree[rson].val;
	}

	void build(int L , int R , int o){
		tree[o].L = L , tree[o].R = R , tree[o].lazy=0 , tree[o].val[0] = 1;
		if (R > L){
			int mid = (L+R) >> 1;
			build(L,mid,o<<1);
			build(mid+1,R,o<<1|1);
		}
	}

	void updata(int QL,int QR,SgTreeDataType v,int o){
		int L = tree[o].L , R = tree[o].R;
		if (QL <= L && R <= QR) tree[o].updata(v);
		else{
			push_down(o);
			int mid = (L+R)>>1;
			if (QL <= mid) updata(QL,QR,v,o<<1);
			if (QR >  mid) updata(QL,QR,v,o<<1|1);
			push_up(o);
		}
	}

	bitset < BitSize > query(int QL,int QR,int o){
		int L = tree[o].L , R = tree[o].R;
		if (QL <= L && R <= QR) return tree[o].val;
		else{
			push_down(o);
			int mid = (L+R)>>1;
			bitset < BitSize > res ; res.reset();
			if (QL <= mid) res |= query(QL,QR,o<<1);
			if (QR > mid) res |= query(QL,QR,o<<1|1);
			push_up(o);
			return res;
		}
	}
}Sgtree;

void link(int u , int v){
	e[tot].v=v,e[tot].nxt=head[u],head[u]=tot++;
}

void dfs(int u , int fa){
	in[u] = ++ dfs_clock;
	for(int i = head[u] ; ~i ; i = e[i].nxt){
		int v = e[i].v;
		if( v == fa ) continue;
		dfs( v , u );
	}
	out[u] = dfs_clock;
}

int main(int argc,char *argv[]){
	memset( head , -1 , sizeof( head ) );
	scanf("%d%d",&n,&m);
	for(int i = 1 ; i <= n ; ++ i) scanf("%d" , p + i );
	init_prime();
	for(int i = 1 ; i < n ; ++ i){
		int u , v ;
		scanf("%d%d" ,&u,&v);
		link( u , v ) ; link( v , u );
	}
	dfs( 1 , 0 );
	Sgtree.build( 1 , dfs_clock , 1 );
	for(int i = 1 ; i <= n ; ++ i) Sgtree.updata( in[i] , in[i] , p[i] % m , 1 );
	scanf("%d",&Q);
	while(Q--){
		int x , y , z;
		scanf("%d%d",&x,&y);
		if( x == 1 ){
			scanf("%d",&z);
			z %= m;
			Sgtree.updata( in[y] , out[y] , z , 1 );
		}else{
			bitset < BitSize > ans = Sgtree.query( in[y] , out[y] , 1 );
			ans &= prime;
			printf("%d\n" , ans.count() );
		}
	}
	return 0;
}


#include <bits/stdc++.h>

using namespace std;
const int BitSize = 1000;
const int maxn = 1e5 + 500;
int head[maxn] , tot , Q , n , m , vis[1500] , in[maxn] , out[maxn] , dfs_clock , p[maxn];
struct edge{
	int v , nxt;
}e[maxn << 1];

bitset < BitSize > prime;

bitset < BitSize > Left_shift( const bitset < BitSize > & a , int b ){
	return a << b | ( a >> ( BitSize - b ) );
}

void init_prime(){
	for(int i = 2 ; i < m ; ++ i)
		if(!vis[i]){
			prime.set( i );
			for(int j = i * 2 ; j < m ; j += i) vis[j] = 1;
		}
}

struct Segmenttree
{
	typedef int SgTreeDataType;
	struct treenode
	{
	  int L , R  , lazy ;
	  bitset < BitSize > val;
	  void updata(SgTreeDataType v){
	  	val = Left_shift( val , v );
	  	lazy += v;
	  	if( lazy >= BitSize ) lazy -= BitSize;
	  }
	};

	treenode tree[maxn * 4];

	inline void push_down(int o){
		int lson = o << 1 , rson = o << 1 | 1;
		if(tree[o].lazy == 0) return;
		tree[lson].updata(tree[o].lazy) ; tree[rson].updata(tree[o].lazy);
		tree[o].lazy = 0;
	}

	inline void push_up(int o){
		int lson = o << 1 , rson = o << 1 | 1;
		tree[o].val = tree[lson].val | tree[rson].val;
	}

	void build(int L , int R , int o){
		tree[o].L = L , tree[o].R = R,tree[o].val.reset();tree[o].val[0]=1;tree[o].lazy=0;
		if (R > L){
			int mid = (L+R) >> 1;
			build(L,mid,o<<1);
			build(mid+1,R,o<<1|1);
		}
	}

	void updata(int QL,int QR,SgTreeDataType v,int o){
		int L = tree[o].L , R = tree[o].R;
		if (QL <= L && R <= QR) tree[o].updata(v);
		else{
			push_down(o);
			int mid = (L+R)>>1;
			if (QL <= mid) updata(QL,QR,v,o<<1);
			if (QR >  mid) updata(QL,QR,v,o<<1|1);
			push_up(o);
		}
	}

	SgTreeDataType query(int QL,int QR,int o){
		int L = tree[o].L , R = tree[o].R;
		if (QL <= L && R <= QR) return (prime&tree[o].val).count();
		else{
			push_down(o);
			int mid = (L+R)>>1;
			SgTreeDataType res = 0;
			if (QL <= mid) res += query(QL,QR,o<<1);
			if (QR > mid) res += query(QL,QR,o<<1|1);
			push_up(o);
			return res;
		}
	}
}Sgtree;

void link(int u , int v){
	e[tot].v=v,e[tot].nxt=head[u],head[u]=tot++;
}

void dfs(int u , int fa){
	in[u] = ++ dfs_clock;
	for(int i = head[u] ; ~i ; i = e[i].nxt){
		int v = e[i].v;
		if( v == fa ) continue;
		dfs( v , u );
	}
	out[u] = dfs_clock;
}

int main(int argc,char *argv[]){
	memset( head , -1 , sizeof( head ) );
	scanf("%d%d",&n,&m);
	for(int i = 1 ; i <= n ; ++ i) scanf("%d" , p + i );
	init_prime();
	for(int i = 1 ; i < n ; ++ i){
		int u , v ;
		scanf("%d%d" ,&u,&v);
		link( u , v ) ; link( v , u );
	}
	dfs( 1 , 0 );
	Sgtree.build( 1 , n , 1 );
	for(int i = 1 ; i <= n ; ++ i) Sgtree.updata( in[i] , in[i] , p[i] , 1 );
	scanf("%d",&Q);
	while(Q--){
		int x , y , z;
		scanf("%d%d",&x,&y);
		if( x == 1 ){
			scanf("%d",&z);
			z %= BitSize;
			Sgtree.updata( in[y] , out[y] , z , 1 );
		}else printf("%d\n" , Sgtree.query( in[y] , out[y] , 1 ));
	}
	return 0;
}


#include <assert.h>
#include <memory.h>
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

#define pb push_back
#define INF 1011111111
#define FOR(i, a, b) for (int _n(b), i(a); i < _n; i++)
#define rep(i, n) FOR(i, 0, n)
#define CL(a, v) memset((a), (v), sizeof(a))
#define mp make_pair
#define X first
#define Y second
#define all(c) (c).begin(), (c).end()
#define SORT(c) sort(all(c))

typedef long long ll;
typedef vector<int> VI;
typedef pair<int, int> pii;

/*** TEMPLATE CODE ENDS HERE */

const int N = 1e5 + 10;
VI g[N];
int a[N], pos[N], fin[N], w[N], kw;

void dfs(int v, int from) {
  pos[v] = kw;
  w[kw++] = v;
  for (int to : g[v]) {
    if (to != from) {
      dfs(to, v);
    }
  }
  fin[v] = kw - 1;
}

const int M = 1000;
int m;
bitset<M> tree[4 * N];
int shift[4 & N];
bitset<M> al;

// void build(int x, int l, int r) {
//  shift[x] = 0;
//  if (l == r) {
//    tree[x] = bitset<M>();
//    tree[x].set(a[w[l]]);
//    return;
//  }
//  int y = (l + r) >> 1;
//  build(x + x, l, y);
//  build(x + x + 1, y + 1, r);
//  tree[x] = tree[x + x] | tree[x + x + 1];
//}
//
// inline void apply(bitset<M> &b, int sh) {
//  b = ((b << sh) & al) | (b >> (m - sh));
//}
//
// inline void push(int x) {
//  if (shift[x] != 0) {
//    shift[x + x] += shift[x];
//    if (shift[x + x] >= m) {
//      shift[x + x] -= m;
//    }
//    shift[x + x + 1] += shift[x];
//    if (shift[x + x + 1] >= m) {
//      shift[x + x + 1] -= m;
//    }
//    apply(tree[x + x], shift[x]);
//    apply(tree[x + x + 1], shift[x]);
//    shift[x] = 0;
//  }
//}
//
// inline void gather(int x) { tree[x] = tree[x + x] | tree[x + x + 1]; }
//
// void modify(int x, int l, int r, int ll, int rr, int sh) {
//  if (ll <= l && r <= rr) {
//    apply(tree[x], sh);
//    shift[x] += sh;
//    if (shift[x] >= m) {
//      shift[x] -= m;
//    }
//    return;
//  }
//  push(x);
//  int y = (l + r) >> 1;
//  if (ll <= y) {
//    modify(x + x, l, y, ll, rr, sh);
//  }
//  if (rr > y) {
//    modify(x + x + 1, y + 1, r, ll, rr, sh);
//  }
//  gather(x);
//}
//
// bitset<M> res;
//
// void get(int x, int l, int r, int ll, int rr) {
//  if (ll <= l && r <= rr) {
//    res |= tree[x];
//    return;
//  }
//  push(x);
//  int y = (l + r) >> 1;
//  if (ll <= y) {
//    get(x + x, l, y, ll, rr);
//  }
//  if (rr > y) {
//    get(x + x + 1, y + 1, r, ll, rr);
//  }
//  gather(x);
//}

void build(int x, int l, int r) {
  shift[x] = 0;
  if (l == r) {
    tree[x] = bitset<M>();
    tree[x].set(a[w[l]]);
    return;
  }
  int y = (l + r) >> 1;
  build(x + x, l, y);
  build(x + x + 1, y + 1, r);
  tree[x] = tree[x + x] | tree[x + x + 1];
}

inline void apply(bitset<M> &b, int sh) {
  b = ((b << sh) & al) | (b >> (m - sh));
}

inline void push(int x) {
  if (shift[x] != 0) {
    shift[x + x] += shift[x];
    if (shift[x + x] >= m) {
      shift[x + x] -= m;
    }
    shift[x + x + 1] += shift[x];
    if (shift[x + x + 1] >= m) {
      shift[x + x + 1] -= m;
    }
    apply(tree[x + x], shift[x]);
    apply(tree[x + x + 1], shift[x]);
    shift[x] = 0;
  }
}

inline void gather(int x) { tree[x] = tree[x + x] | tree[x + x + 1]; }

void modify(int x, int l, int r, int ll, int rr, int sh) {
  if (ll <= l && r <= rr) {
    apply(tree[x], sh);
    shift[x] += sh;
    if (shift[x] >= m) {
      shift[x] -= m;
    }
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    modify(x + x, l, y, ll, rr, sh);
  }
  if (rr > y) {
    modify(x + x + 1, y + 1, r, ll, rr, sh);
  }
  gather(x);
}

bitset<M> res;

void get(int x, int l, int r, int ll, int rr) {
  if (ll <= l && r <= rr) {
    res |= tree[x];
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    get(x + x, l, y, ll, rr);
  }
  if (rr > y) {
    get(x + x + 1, y + 1, r, ll, rr);
  }
  gather(x);
}

int main() {
#ifdef LOCAL_HOST
  freopen("input.txt", "r", stdin);
// freopen("output.txt","w",stdout);
#endif

  ios_base::sync_with_stdio(false);

  //  int n;
  //  cin >> n >> m;
  //  rep(i, n) {
  //    cin >> a[i];
  //    a[i] %= m;
  //  }
  //  rep(i, n - 1) {
  //    int x, y;
  //    cin >> x >> y;
  //    --x, --y;
  //    g[x].pb(y);
  //    g[y].pb(x);
  //  }
  //
  //  kw = 0;
  //  dfs(0, -1);
  //  build(1, 0, n - 1);
  //
  //  bitset<M> primes;
  //  rep(i, m) al.set(i);
  //
  //  for (int i = 2; i < m; i++) {
  //    bool prime = true;
  //    for (int j = 2; j * j <= i; j++) {
  //      if (i % j == 0) {
  //        prime = false;
  //        break;
  //      }
  //    }
  //    if (prime) {
  //      primes.set(i);
  //    }
  //  }
  //
  //  int q;
  //  cin >> q;
  //  while (q--) {
  //    int op, v;
  //    cin >> op >> v;
  //    --v;
  //    if (op == 1) {
  //      int shift;
  //      cin >> shift;
  //      shift %= m;
  //      if (shift) {
  //        modify(1, 0, n - 1, pos[v], fin[v], shift);
  //      }
  //    } else {
  //      res.reset();
  //      get(1, 0, n - 1, pos[v], fin[v]);
  //      int ans = int((res & primes).count());
  //      cout << ans << endl;
  //    }
  //  }
  int n;
  cin >> n >> m;
  for (int i = 0; i < n; i++) {
    cin >> a[i];
    a[i] %= m;
  }
  for (int i = 0; i < n; i++) {
    g[i].clear();
  }
  for (int i = 0; i < n - 1; i++) {
    int foo, bar;
    cin >> foo >> bar;
    foo--;
    bar--;
    g[foo].push_back(bar);
    g[bar].push_back(foo);
  }
  kw = 0;
  dfs(0, -1);
  build(1, 0, n - 1);
  bitset<M> primes;
  for (int i = 0; i < m; i++) {
    al.set(i);
  }
  for (int i = 2; i < m; i++) {
    bool prime = true;
    for (int j = 2; j * j <= i; j++) {
      if (i % j == 0) {
        prime = false;
        break;
      }
    }
    if (prime) {
      primes.set(i);
    }
  }
  int tt;
  cin >> tt;
  while (tt--) {
    int type, v;
    cin >> type >> v;
    v--;
    if (type == 1) {
      int shift;
      cin >> shift;
      shift %= m;
      if (shift == 0) {
        continue;
      }
      modify(1, 0, n - 1, pos[v], fin[v], shift);
    } else {
      res.reset();
      get(1, 0, n - 1, pos[v], fin[v]);
      int ans = int((res & primes).count());
      cout << ans << endl;
    }
  }

#ifdef LOCAL_HOST
  printf("TIME: %.3lf\n", double(clock()) / CLOCKS_PER_SEC);
#endif

  return 0;
}


#include <assert.h>
#include <memory.h>
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

#define pb push_back
#define INF 1011111111
#define FOR(i, a, b) for (int _n(b), i(a); i < _n; i++)
#define rep(i, n) FOR(i, 0, n)
#define CL(a, v) memset((a), (v), sizeof(a))
#define mp make_pair
#define X first
#define Y second
#define all(c) (c).begin(), (c).end()
#define SORT(c) sort(all(c))

typedef long long ll;
typedef vector<int> VI;
typedef pair<int, int> pii;

/*** TEMPLATE CODE ENDS HERE */

const int N = 1e5 + 10;
VI g[N];
int a[N], pos[N], fin[N], w[N], kw;

void dfs(int v, int from) {
  pos[v] = kw;
  w[kw++] = v;
  for (int to : g[v]) {
    if (to != from) {
      dfs(to, v);
    }
  }
  fin[v] = kw - 1;
}

const int M = 1000;
int m;
bitset<M> tree[4 * N];
int shift[4 & N];
bitset<M> al;

void build(int x, int l, int r) {
  shift[x] = 0;
  if (l == r) {
    tree[x] = bitset<M>();
    tree[x].set(a[w[l]]);
    return;
  }
  int y = (l + r) >> 1;
  build(x + x, l, y);
  build(x + x + 1, y + 1, r);
  tree[x] = tree[x + x] | tree[x + x + 1];
}

inline void apply(bitset<M> &b, int sh) {
  b = ((b << sh) & al) | (b >> (m - sh));
}

inline void push(int x) {
  if (shift[x] != 0) {
    shift[x + x] += shift[x];
    if (shift[x + x] >= m) {
      shift[x + x] -= m;
    }
    shift[x + x + 1] += shift[x];
    if (shift[x + x + 1] >= m) {
      shift[x + x + 1] -= m;
    }
    apply(tree[x + x], shift[x]);
    apply(tree[x + x + 1], shift[x]);
    shift[x] = 0;
  }
}

inline void gather(int x) { tree[x] = tree[x + x] | tree[x + x + 1]; }

void modify(int x, int l, int r, int ll, int rr, int sh) {
  if (ll <= l && r <= rr) {
    apply(tree[x], sh);
    shift[x] += sh;
    if (shift[x] >= m) {
      shift[x] -= m;
    }
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    modify(x + x, l, y, ll, rr, sh);
  }
  if (rr > y) {
    modify(x + x + 1, y + 1, r, ll, rr, sh);
  }
  gather(x);
}

bitset<M> res;

void get(int x, int l, int r, int ll, int rr) {
  if (ll <= l && r <= rr) {
    res |= tree[x];
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    get(x + x, l, y, ll, rr);
  }
  if (rr > y) {
    get(x + x + 1, y + 1, r, ll, rr);
  }
  gather(x);
}

int main() {
#ifdef LOCAL_HOST
  freopen("input.txt", "r", stdin);
// freopen("output.txt","w",stdout);
#endif

  ios_base::sync_with_stdio(false);

  //  int n;
  //  cin >> n >> m;
  //  rep(i, n) {
  //    cin >> a[i];
  //    a[i] %= m;
  //  }
  //  rep(i, n - 1) {
  //    int x, y;
  //    cin >> x >> y;
  //    --x, --y;
  //    g[x].pb(y);
  //    g[y].pb(x);
  //  }
  //
  //  kw = 0;
  //  dfs(0, -1);
  //  build(1, 0, n - 1);
  //
  //  bitset<M> primes;
  //  rep(i, m) al.set(i);
  //
  //  for (int i = 2; i < m; i++) {
  //    bool prime = true;
  //    for (int j = 2; j * j <= i; j++) {
  //      if (i % j == 0) {
  //        prime = false;
  //        break;
  //      }
  //    }
  //    if (prime) {
  //      primes.set(i);
  //    }
  //  }
  //
  //  int q;
  //  cin >> q;
  //  while (q--) {
  //    int op, v;
  //    cin >> op >> v;
  //    --v;
  //    if (op == 1) {
  //      int shift;
  //      cin >> shift;
  //      shift %= m;
  //      if (shift) {
  //        modify(1, 0, n - 1, pos[v], fin[v], shift);
  //      }
  //    } else {
  //      res.reset();
  //      get(1, 0, n - 1, pos[v], fin[v]);
  //      int ans = int((res & primes).count());
  //      cout << ans << endl;
  //    }
  //  }
  int n;
  cin >> n >> m;
  for (int i = 0; i < n; i++) {
    cin >> a[i];
    a[i] %= m;
  }
  for (int i = 0; i < n; i++) {
    g[i].clear();
  }
  for (int i = 0; i < n - 1; i++) {
    int foo, bar;
    cin >> foo >> bar;
    foo--;
    bar--;
    g[foo].push_back(bar);
    g[bar].push_back(foo);
  }
  kw = 0;
  dfs(0, -1);
  build(1, 0, n - 1);
  bitset<M> primes;
  for (int i = 0; i < m; i++) {
    al.set(i);
  }
  for (int i = 2; i < m; i++) {
    bool prime = true;
    for (int j = 2; j * j <= i; j++) {
      if (i % j == 0) {
        prime = false;
        break;
      }
    }
    if (prime) {
      primes.set(i);
    }
  }
  int tt;
  cin >> tt;
  while (tt--) {
    int type, v;
    cin >> type >> v;
    v--;
    if (type == 1) {
      int shift;
      cin >> shift;
      shift %= m;
      if (shift == 0) {
        continue;
      }
      modify(1, 0, n - 1, pos[v], fin[v], shift);
    } else {
      res.reset();
      get(1, 0, n - 1, pos[v], fin[v]);
      int ans = int((res & primes).count());
      cout << ans << endl;
    }
  }

#ifdef LOCAL_HOST
  printf("TIME: %.3lf\n", double(clock()) / CLOCKS_PER_SEC);
#endif

  return 0;
}


#include <assert.h>
#include <memory.h>
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

#define pb push_back
#define INF 1011111111
#define FOR(i, a, b) for (int _n(b), i(a); i < _n; i++)
#define rep(i, n) FOR(i, 0, n)
#define CL(a, v) memset((a), (v), sizeof(a))
#define mp make_pair
#define X first
#define Y second
#define all(c) (c).begin(), (c).end()
#define SORT(c) sort(all(c))

typedef long long ll;
typedef vector<int> VI;
typedef pair<int, int> pii;

/*** TEMPLATE CODE ENDS HERE */

const int N = 1e5 + 10;
VI g[N];
int a[N], pos[N], fin[N], w[N], kw;

void dfs(int v, int from) {
  pos[v] = kw;
  w[kw++] = v;
  for (int to : g[v]) {
    if (to != from) {
      dfs(to, v);
    }
  }
  fin[v] = kw - 1;
}

const int M = 1000;
int m;
bitset<M> tree[4 * N];
int shift[4 & N];
bitset<M> al;

void build(int x, int l, int r) {
  shift[x] = 0;
  if (l == r) {
    tree[x] = bitset<M>();
    tree[x].set(a[w[l]]);
    return;
  }
  int y = (l + r) >> 1;
  build(x + x, l, y);
  build(x + x + 1, y + 1, r);
  tree[x] = tree[x + x] | tree[x + x + 1];
}

inline void apply(bitset<M> &b, int sh) {
  b = ((b << sh) & al) | (b >> (m - sh));
}

inline void push(int x) {
  if (shift[x] != 0) {
    shift[x + x] += shift[x];
    if (shift[x + x] >= m) {
      shift[x + x] -= m;
    }
    shift[x + x + 1] += shift[x];
    if (shift[x + x + 1] >= m) {
      shift[x + x + 1] -= m;
    }
    apply(tree[x + x], shift[x]);
    apply(tree[x + x + 1], shift[x]);
    shift[x] = 0;
  }
}

inline void gather(int x) { tree[x] = tree[x + x] | tree[x + x + 1]; }

void modify(int x, int l, int r, int ll, int rr, int sh) {
  if (ll <= l && r <= rr) {
    apply(tree[x], sh);
    shift[x] += sh;
    if (shift[x] >= m) {
      shift[x] -= m;
    }
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    modify(x + x, l, y, ll, rr, sh);
  }
  if (rr > y) {
    modify(x + x + 1, y + 1, r, ll, rr, sh);
  }
  gather(x);
}

bitset<M> res;

void get(int x, int l, int r, int ll, int rr) {
  if (ll <= l && r <= rr) {
    res |= tree[x];
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    get(x + x, l, y, ll, rr);
  }
  if (rr > y) {
    get(x + x + 1, y + 1, r, ll, rr);
  }
  gather(x);
}

int main() {
#ifdef LOCAL_HOST
  freopen("input.txt", "r", stdin);
// freopen("output.txt","w",stdout);
#endif

  ios_base::sync_with_stdio(false);

  int n;
  cin >> n >> m;
  rep(i, n) {
    cin >> a[i];
    a[i] %= m;
  }
  rep(i, n - 1) {
    int x, y;
    cin >> x >> y;
    --x, --y;
    g[x].pb(y);
    g[y].pb(x);
  }

  kw = 0;
  dfs(0, -1);
  build(1, 0, n - 1);

  bitset<M> primes;
  rep(i, m) al.set(i);

  for (int i = 2; i < m; i++) {
    bool prime = true;
    for (int j = 2; j * j <= i; j++) {
      if (i % j == 0) {
        prime = false;
        break;
      }
    }
    if (prime) {
      primes.set(i);
    }
  }

  int q;
  cin >> q;
  while (q-- > 0) {
    int op, v;
    cin >> op >> v;
    --v;
    if (op == 1) {
      int shift;
      cin >> shift;
      shift %= m;
      if (shift == 0) continue;
      modify(1, 0, n - 1, pos[v], fin[v], shift);
    } else {
      res.reset();
      get(1, 0, n - 1, pos[v], fin[v]);
      int ans = int((res & primes).count());
      cout << ans << endl;
    }
  }

#ifdef LOCAL_HOST
  printf("TIME: %.3lf\n", double(clock()) / CLOCKS_PER_SEC);
#endif

  return 0;
}


#include <assert.h>
#include <memory.h>
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

#define pb push_back
#define INF 1011111111
#define FOR(i, a, b) for (int _n(b), i(a); i < _n; i++)
#define rep(i, n) FOR(i, 0, n)
#define CL(a, v) memset((a), (v), sizeof(a))
#define mp make_pair
#define X first
#define Y second
#define all(c) (c).begin(), (c).end()
#define SORT(c) sort(all(c))

typedef long long ll;
typedef vector<int> VI;
typedef pair<int, int> pii;

/*** TEMPLATE CODE ENDS HERE */

const int N = 1e5 + 10;
VI g[N];
int a[N], pos[N], fin[N], w[N], kw;

// void dfs(int v, int from) {
//  pos[v] = kw;
//  w[kw++] = v;
//  for (int to : g[v]) {
//    if (to != from) {
//      dfs(to, v);
//    }
//  }
//  fin[v] = kw - 1;
//}

void dfs(int v, int pr) {
  pos[v] = kw;
  w[kw++] = v;
  int sz = (int)g[v].size();
  for (int j = 0; j < sz; j++) {
    int u = g[v][j];
    if (u == pr) {
      continue;
    }
    dfs(u, v);
  }
  fin[v] = kw - 1;
}

const int M = 1000;
int m;
bitset<M> tree[4 * N];
int shift[4 * N];
bitset<M> al;

// void build(int x, int l, int r) {
//  shift[x] = 0;
//  if (l == r) {
//    tree[x] = bitset<M>();
//    tree[x].set(a[w[l]]);
//    return;
//  }
//  int y = (l + r) >> 1;
//  build(x + x, l, y);
//  build(x + x + 1, y + 1, r);
//  tree[x] = tree[x + x] | tree[x + x + 1];
//}
//
// inline void apply(bitset<M> &b, int sh) {
//  b = ((b << sh) & al) | (b >> (m - sh));
//}
//
// inline void push(int x) {
//  if (shift[x] != 0) {
//    shift[x + x] += shift[x];
//    if (shift[x + x] >= m) {
//      shift[x + x] -= m;
//    }
//    shift[x + x + 1] += shift[x];
//    if (shift[x + x + 1] >= m) {
//      shift[x + x + 1] -= m;
//    }
//    apply(tree[x + x], shift[x]);
//    apply(tree[x + x + 1], shift[x]);
//    shift[x] = 0;
//  }
//}
//
// inline void gather(int x) { tree[x] = tree[x + x] | tree[x + x + 1]; }
//
// void modify(int x, int l, int r, int ll, int rr, int sh) {
//  if (ll <= l && r <= rr) {
//    apply(tree[x], sh);
//    shift[x] += sh;
//    if (shift[x] >= m) {
//      shift[x] -= m;
//    }
//    return;
//  }
//  push(x);
//  int y = (l + r) >> 1;
//  if (ll <= y) {
//    modify(x + x, l, y, ll, rr, sh);
//  }
//  if (rr > y) {
//    modify(x + x + 1, y + 1, r, ll, rr, sh);
//  }
//  gather(x);
//}
//
// bitset<M> res;
//
// void get(int x, int l, int r, int ll, int rr) {
//  if (ll <= l && r <= rr) {
//    res |= tree[x];
//    return;
//  }
//  push(x);
//  int y = (l + r) >> 1;
//  if (ll <= y) {
//    get(x + x, l, y, ll, rr);
//  }
//  if (rr > y) {
//    get(x + x + 1, y + 1, r, ll, rr);
//  }
//  gather(x);
//}

void build(int x, int l, int r) {
  shift[x] = 0;
  if (l == r) {
    tree[x] = bitset<M>();
    tree[x].set(a[w[l]]);
    return;
  }
  int y = (l + r) >> 1;
  build(x + x, l, y);
  build(x + x + 1, y + 1, r);
  tree[x] = tree[x + x] | tree[x + x + 1];
}

inline void apply(bitset<M> &b, int sh) {
  b = ((b << sh) & al) | (b >> (m - sh));
}

inline void push(int x) {
  if (shift[x] != 0) {
    shift[x + x] += shift[x];
    if (shift[x + x] >= m) {
      shift[x + x] -= m;
    }
    shift[x + x + 1] += shift[x];
    if (shift[x + x + 1] >= m) {
      shift[x + x + 1] -= m;
    }
    apply(tree[x + x], shift[x]);
    apply(tree[x + x + 1], shift[x]);
    shift[x] = 0;
  }
}

inline void gather(int x) { tree[x] = tree[x + x] | tree[x + x + 1]; }

void modify(int x, int l, int r, int ll, int rr, int sh) {
  if (ll <= l && r <= rr) {
    apply(tree[x], sh);
    shift[x] += sh;
    if (shift[x] >= m) {
      shift[x] -= m;
    }
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    modify(x + x, l, y, ll, rr, sh);
  }
  if (rr > y) {
    modify(x + x + 1, y + 1, r, ll, rr, sh);
  }
  gather(x);
}

bitset<M> res;

void get(int x, int l, int r, int ll, int rr) {
  if (ll <= l && r <= rr) {
    res |= tree[x];
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    get(x + x, l, y, ll, rr);
  }
  if (rr > y) {
    get(x + x + 1, y + 1, r, ll, rr);
  }
  gather(x);
}

int main() {
#ifdef LOCAL_HOST
  freopen("input.txt", "r", stdin);
// freopen("output.txt","w",stdout);
#endif

  ios_base::sync_with_stdio(false);

  //  int n;
  //  cin >> n >> m;
  //  rep(i, n) {
  //    cin >> a[i];
  //    a[i] %= m;
  //  }
  //  rep(i, n - 1) {
  //    int x, y;
  //    cin >> x >> y;
  //    --x, --y;
  //    g[x].pb(y);
  //    g[y].pb(x);
  //  }
  //
  //  kw = 0;
  //  dfs(0, -1);
  //  build(1, 0, n - 1);
  //
  //  bitset<M> primes;
  //  rep(i, m) al.set(i);
  //
  //  for (int i = 2; i < m; i++) {
  //    bool prime = true;
  //    for (int j = 2; j * j <= i; j++) {
  //      if (i % j == 0) {
  //        prime = false;
  //        break;
  //      }
  //    }
  //    if (prime) {
  //      primes.set(i);
  //    }
  //  }
  //
  //  int q;
  //  cin >> q;
  //  while (q--) {
  //    int op, v;
  //    cin >> op >> v;
  //    --v;
  //    if (op == 1) {
  //      int shift;
  //      cin >> shift;
  //      shift %= m;
  //      if (shift) {
  //        modify(1, 0, n - 1, pos[v], fin[v], shift);
  //      }
  //    } else {
  //      res.reset();
  //      get(1, 0, n - 1, pos[v], fin[v]);
  //      int ans = int((res & primes).count());
  //      cout << ans << endl;
  //    }
  //  }
  int n;
  cin >> n >> m;
  for (int i = 0; i < n; i++) {
    cin >> a[i];
    a[i] %= m;
  }
  for (int i = 0; i < n; i++) {
    g[i].clear();
  }
  for (int i = 0; i < n - 1; i++) {
    int foo, bar;
    cin >> foo >> bar;
    foo--;
    bar--;
    g[foo].push_back(bar);
    g[bar].push_back(foo);
  }
  kw = 0;
  dfs(0, -1);
  build(1, 0, n - 1);
  bitset<M> primes;
  for (int i = 0; i < m; i++) {
    al.set(i);
  }
  for (int i = 2; i < m; i++) {
    bool prime = true;
    for (int j = 2; j * j <= i; j++) {
      if (i % j == 0) {
        prime = false;
        break;
      }
    }
    if (prime) {
      primes.set(i);
    }
  }
  int tt;
  cin >> tt;
  while (tt--) {
    int type, v;
    cin >> type >> v;
    v--;
    if (type == 1) {
      int shift;
      cin >> shift;
      shift %= m;
      if (shift == 0) {
        continue;
      }
      modify(1, 0, n - 1, pos[v], fin[v], shift);
    } else {
      res.reset();
      get(1, 0, n - 1, pos[v], fin[v]);
      int ans = int((res & primes).count());
      cout << ans << endl;
    }
  }

#ifdef LOCAL_HOST
  printf("TIME: %.3lf\n", double(clock()) / CLOCKS_PER_SEC);
#endif

  return 0;
}


#include <assert.h>
#include <memory.h>
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

#define pb push_back
#define INF 1011111111
#define FOR(i, a, b) for (int _n(b), i(a); i < _n; i++)
#define rep(i, n) FOR(i, 0, n)
#define CL(a, v) memset((a), (v), sizeof(a))
#define mp make_pair
#define X first
#define Y second
#define all(c) (c).begin(), (c).end()
#define SORT(c) sort(all(c))

typedef long long ll;
typedef vector<int> VI;
typedef pair<int, int> pii;

/*** TEMPLATE CODE ENDS HERE */

const int N = 1e5 + 10;
VI g[N];
int a[N], pos[N], fin[N], w[N], kw;

// void dfs(int v, int from) {
//  pos[v] = kw;
//  w[kw++] = v;
//  for (int to : g[v]) {
//    if (to != from) {
//      dfs(to, v);
//    }
//  }
//  fin[v] = kw - 1;
//}

void dfs(int v, int pr) {
  pos[v] = kw;
  w[kw++] = v;
  int sz = (int)g[v].size();
  for (int j = 0; j < sz; j++) {
    int u = g[v][j];
    if (u == pr) {
      continue;
    }
    dfs(u, v);
  }
  fin[v] = kw - 1;
}

const int M = 1000;
int m;
bitset<M> tree[4 * N];
int shift[4 & N];
bitset<M> al;

// void build(int x, int l, int r) {
//  shift[x] = 0;
//  if (l == r) {
//    tree[x] = bitset<M>();
//    tree[x].set(a[w[l]]);
//    return;
//  }
//  int y = (l + r) >> 1;
//  build(x + x, l, y);
//  build(x + x + 1, y + 1, r);
//  tree[x] = tree[x + x] | tree[x + x + 1];
//}
//
// inline void apply(bitset<M> &b, int sh) {
//  b = ((b << sh) & al) | (b >> (m - sh));
//}
//
// inline void push(int x) {
//  if (shift[x] != 0) {
//    shift[x + x] += shift[x];
//    if (shift[x + x] >= m) {
//      shift[x + x] -= m;
//    }
//    shift[x + x + 1] += shift[x];
//    if (shift[x + x + 1] >= m) {
//      shift[x + x + 1] -= m;
//    }
//    apply(tree[x + x], shift[x]);
//    apply(tree[x + x + 1], shift[x]);
//    shift[x] = 0;
//  }
//}
//
// inline void gather(int x) { tree[x] = tree[x + x] | tree[x + x + 1]; }
//
// void modify(int x, int l, int r, int ll, int rr, int sh) {
//  if (ll <= l && r <= rr) {
//    apply(tree[x], sh);
//    shift[x] += sh;
//    if (shift[x] >= m) {
//      shift[x] -= m;
//    }
//    return;
//  }
//  push(x);
//  int y = (l + r) >> 1;
//  if (ll <= y) {
//    modify(x + x, l, y, ll, rr, sh);
//  }
//  if (rr > y) {
//    modify(x + x + 1, y + 1, r, ll, rr, sh);
//  }
//  gather(x);
//}
//
// bitset<M> res;
//
// void get(int x, int l, int r, int ll, int rr) {
//  if (ll <= l && r <= rr) {
//    res |= tree[x];
//    return;
//  }
//  push(x);
//  int y = (l + r) >> 1;
//  if (ll <= y) {
//    get(x + x, l, y, ll, rr);
//  }
//  if (rr > y) {
//    get(x + x + 1, y + 1, r, ll, rr);
//  }
//  gather(x);
//}

void build(int x, int l, int r) {
  shift[x] = 0;
  if (l == r) {
    tree[x] = bitset<M>();
    tree[x].set(a[w[l]]);
    return;
  }
  int y = (l + r) >> 1;
  build(x + x, l, y);
  build(x + x + 1, y + 1, r);
  tree[x] = tree[x + x] | tree[x + x + 1];
}

inline void apply(bitset<M> &b, int sh) {
  b = ((b << sh) & al) | (b >> (m - sh));
}

inline void push(int x) {
  if (shift[x] != 0) {
    shift[x + x] += shift[x];
    if (shift[x + x] >= m) {
      shift[x + x] -= m;
    }
    shift[x + x + 1] += shift[x];
    if (shift[x + x + 1] >= m) {
      shift[x + x + 1] -= m;
    }
    apply(tree[x + x], shift[x]);
    apply(tree[x + x + 1], shift[x]);
    shift[x] = 0;
  }
}

inline void gather(int x) { tree[x] = tree[x + x] | tree[x + x + 1]; }

void modify(int x, int l, int r, int ll, int rr, int sh) {
  if (ll <= l && r <= rr) {
    apply(tree[x], sh);
    shift[x] += sh;
    if (shift[x] >= m) {
      shift[x] -= m;
    }
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    modify(x + x, l, y, ll, rr, sh);
  }
  if (rr > y) {
    modify(x + x + 1, y + 1, r, ll, rr, sh);
  }
  gather(x);
}

bitset<M> res;

void get(int x, int l, int r, int ll, int rr) {
  if (ll <= l && r <= rr) {
    res |= tree[x];
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    get(x + x, l, y, ll, rr);
  }
  if (rr > y) {
    get(x + x + 1, y + 1, r, ll, rr);
  }
  gather(x);
}

int main() {
#ifdef LOCAL_HOST
  freopen("input.txt", "r", stdin);
// freopen("output.txt","w",stdout);
#endif

  ios_base::sync_with_stdio(false);

  //  int n;
  //  cin >> n >> m;
  //  rep(i, n) {
  //    cin >> a[i];
  //    a[i] %= m;
  //  }
  //  rep(i, n - 1) {
  //    int x, y;
  //    cin >> x >> y;
  //    --x, --y;
  //    g[x].pb(y);
  //    g[y].pb(x);
  //  }
  //
  //  kw = 0;
  //  dfs(0, -1);
  //  build(1, 0, n - 1);
  //
  //  bitset<M> primes;
  //  rep(i, m) al.set(i);
  //
  //  for (int i = 2; i < m; i++) {
  //    bool prime = true;
  //    for (int j = 2; j * j <= i; j++) {
  //      if (i % j == 0) {
  //        prime = false;
  //        break;
  //      }
  //    }
  //    if (prime) {
  //      primes.set(i);
  //    }
  //  }
  //
  //  int q;
  //  cin >> q;
  //  while (q--) {
  //    int op, v;
  //    cin >> op >> v;
  //    --v;
  //    if (op == 1) {
  //      int shift;
  //      cin >> shift;
  //      shift %= m;
  //      if (shift) {
  //        modify(1, 0, n - 1, pos[v], fin[v], shift);
  //      }
  //    } else {
  //      res.reset();
  //      get(1, 0, n - 1, pos[v], fin[v]);
  //      int ans = int((res & primes).count());
  //      cout << ans << endl;
  //    }
  //  }
  int n;
  cin >> n >> m;
  for (int i = 0; i < n; i++) {
    cin >> a[i];
    a[i] %= m;
  }
  for (int i = 0; i < n; i++) {
    g[i].clear();
  }
  for (int i = 0; i < n - 1; i++) {
    int foo, bar;
    cin >> foo >> bar;
    foo--;
    bar--;
    g[foo].push_back(bar);
    g[bar].push_back(foo);
  }
  kw = 0;
  dfs(0, -1);
  build(1, 0, n - 1);
  bitset<M> primes;
  for (int i = 0; i < m; i++) {
    al.set(i);
  }
  for (int i = 2; i < m; i++) {
    bool prime = true;
    for (int j = 2; j * j <= i; j++) {
      if (i % j == 0) {
        prime = false;
        break;
      }
    }
    if (prime) {
      primes.set(i);
    }
  }
  int tt;
  cin >> tt;
  while (tt--) {
    int type, v;
    cin >> type >> v;
    v--;
    if (type == 1) {
      int shift;
      cin >> shift;
      shift %= m;
      if (shift == 0) {
        continue;
      }
      modify(1, 0, n - 1, pos[v], fin[v], shift);
    } else {
      res.reset();
      get(1, 0, n - 1, pos[v], fin[v]);
      int ans = int((res & primes).count());
      cout << ans << endl;
    }
  }

#ifdef LOCAL_HOST
  printf("TIME: %.3lf\n", double(clock()) / CLOCKS_PER_SEC);
#endif

  return 0;
}


#include <assert.h>
#include <memory.h>
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

#define pb push_back
#define INF 1011111111
#define FOR(i, a, b) for (int _n(b), i(a); i < _n; i++)
#define rep(i, n) FOR(i, 0, n)
#define CL(a, v) memset((a), (v), sizeof(a))
#define mp make_pair
#define X first
#define Y second
#define all(c) (c).begin(), (c).end()
#define SORT(c) sort(all(c))

typedef long long ll;
typedef vector<int> VI;
typedef pair<int, int> pii;

/*** TEMPLATE CODE ENDS HERE */

const int N = 1e5 + 10;
VI g[N];
int a[N], pos[N], fin[N], w[N], kw;

void dfs(int v, int from) {
  pos[v] = kw;
  w[kw++] = v;
  for (int to : g[v]) {
    if (to != from) {
      dfs(to, v);
    }
  }
  fin[v] = kw - 1;
}

const int M = 1000;
int m;
bitset<M> tree[4 * N];
int shift[4 & N];
bitset<M> al;

inline void gather(int x) { tree[x] = tree[2 * x] | tree[2 * x + 1]; }

void build(int x, int l, int r) {
  shift[x] = 0;
  if (l == r) {
    tree[x] = bitset<M>();
    tree[x].set(a[w[l]]);
    return;
  }
  int y = (l + r) / 2;
  build(2 * x, l, y);
  build(2 * x + 1, y + 1, r);
  gather(x);
}

inline void apply(bitset<M> &b, int sh) {
  b = ((b << sh) & al) | (b >> (m - sh));
}

inline void push(int x) {
  if (shift[x] != 0) {
    shift[2 * x] += shift[x];
    if (shift[2 * x] >= m) {
      shift[2 * x] -= m;
    }
    shift[2 * x + 1] += shift[x];
    if (shift[2 * x + 1] >= m) {
      shift[2 * x + 1] -= m;
    }
    apply(tree[2 * x], shift[x]);
    apply(tree[2 * x + 1], shift[x]);
    shift[x] = 0;
  }
}

void modify(int x, int l, int r, int ll, int rr, int sh) {
  if (ll <= l && r <= rr) {
    apply(tree[x], sh);
    shift[x] += sh;
    if (shift[x] >= m) {
      shift[x] -= m;
    }
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    modify(2 * x, l, y, ll, rr, sh);
  }
  if (rr > y) {
    modify(2 * x + 1, y + 1, r, ll, rr, sh);
  }
}

bitset<M> res;

void get(int x, int l, int r, int ll, int rr) {
  if (ll <= l && r <= rr) {
    res |= tree[x];
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    get(x + x, l, y, ll, rr);
  }
  if (rr > y) {
    get(x + x + 1, y + 1, r, ll, rr);
  }
  gather(x);
}

int main() {
#ifdef LOCAL_HOST
  freopen("input.txt", "r", stdin);
// freopen("output.txt","w",stdout);
#endif

  ios_base::sync_with_stdio(false);

  int n;
  cin >> n >> m;
  rep(i, n) {
    cin >> a[i];
    a[i] %= m;
  }
  rep(i, n - 1) {
    int x, y;
    cin >> x >> y;
    --x, --y;
    g[x].pb(y);
    g[y].pb(x);
  }

  kw = 0;
  dfs(0, -1);
  build(1, 0, n - 1);

  bitset<M> primes;
  rep(i, m) al.set(i);

  for (int i = 2; i < m; i++) {
    bool prime = true;
    for (int j = 2; j * j <= i; j++) {
      if (i % j == 0) {
        prime = false;
        break;
      }
    }
    if (prime) {
      primes.set(i);
    }
  }

  int q;
  cin >> q;
  while (q-- > 0) {
    int op, v;
    cin >> op >> v;
    --v;
    if (op == 1) {
      int shift;
      cin >> shift;
      shift %= m;
      if (shift == 0) continue;
      modify(1, 0, n - 1, pos[v], fin[v], shift);
    } else {
      res.reset();
      get(1, 0, n - 1, pos[v], fin[v]);
      int ans = int((res & primes).count());
      cout << ans << endl;
    }
  }

#ifdef LOCAL_HOST
  printf("TIME: %.3lf\n", double(clock()) / CLOCKS_PER_SEC);
#endif

  return 0;
}


#include <assert.h>
#include <memory.h>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

#define pb push_back
#define INF 1011111111
#define FOR(i, a, b) for (int _n(b), i(a); i < _n; i++)
#define rep(i, n) FOR(i, 0, n)
#define CL(a, v) memset((a), (v), sizeof(a))
#define mp make_pair
#define X first
#define Y second
#define all(c) (c).begin(), (c).end()
#define SORT(c) sort(all(c))

typedef long long ll;
typedef vector<int> VI;
typedef pair<int, int> pii;

/*** TEMPLATE CODE ENDS HERE */

const int N = 1e5 + 10;
VI g[N];
int a[N], pos[N], fin[N], w[N], kw;

void dfs(int v, int from) {
  pos[v] = kw;
  w[kw++] = v;
  for (int to : g[v]) {
    if (to != from) {
      dfs(to, v);
    }
  }
  fin[v] = kw - 1;
}

const int M = 1000;
int m;
bitset<M> tree[4 * N];
int shift[4 & N];
bitset<M> al;

inline void gather(int x) { tree[x] = tree[2 * x] | tree[2 * x + 1]; }

void build(int x, int l, int r) {
  shift[x] = 0;
  if (l == r) {
    tree[x] = bitset<M>();
    tree[x].set(a[w[l]]);
    return;
  }
  int y = (l + r) / 2;
  build(2 * x, l, y);
  build(2 * x + 1, y + 1, r);
  gather(x);
}

inline void apply(bitset<M> &b, int sh) {
  b = ((b << sh) & al) | (b >> (m - sh));
}

inline void push(int x) {
  if (shift[x] != 0) {
    shift[2 * x] += shift[x];
    if (shift[2 * x] >= m) {
      shift[2 * x] -= m;
    }
    shift[2 * x + 1] += shift[x];
    if (shift[2 * x + 1] >= m) {
      shift[2 * x + 1] -= m;
    }
    apply(tree[2 * x], shift[x]);
    apply(tree[2 * x + 1], shift[x]);
    shift[x] = 0;
  }
}

void modify(int x, int l, int r, int ll, int rr, int sh) {
  if (ll <= l && r <= rr) {
    apply(tree[x], sh);
    shift[x] += sh;
    if (shift[x] >= m) {
      shift[x] -= m;
    }
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    modify(2 * x, l, y, ll, rr, sh);
  }
  if (rr > y) {
    modify(2 * x + 1, y + 1, r, ll, rr, sh);
  }
}

bitset<M> res;

void get(int x, int l, int r, int ll, int rr) {
  if (ll <= l && r <= rr) {
    res |= tree[x];
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    get(x + x, l, y, ll, rr);
  }
  if (rr > y) {
    get(x + x + 1, y + 1, r, ll, rr);
  }
  gather(x);
}

int main() {
#ifdef LOCAL_HOST
  freopen("input.txt", "r", stdin);
// freopen("output.txt","w",stdout);
#endif

  ios_base::sync_with_stdio(false);

  int n;
  cin >> n >> m;
  rep(i, n) {
    cin >> a[i];
    a[i] %= m;
  }
  rep(i, n - 1) {
    int x, y;
    cin >> x >> y;
    --x, --y;
    g[x].pb(y);
    g[y].pb(x);
  }

  kw = 0;
  dfs(0, -1);
  build(1, 0, n - 1);

  bitset<M> primes;
  rep(i, m) al.set(i);

  for (int i = 2; i < m; i++) {
    bool prime = true;
    for (int j = 2; j * j <= i; j++) {
      if (i % j == 0) {
        prime = false;
        break;
      }
    }
    if (prime) {
      primes.set(i);
    }
  }

  int q;
  cin >> q;
  while (q-- > 0) {
    int op, v;
    cin >> op >> v;
    --v;
    if (op == 1) {
      int shift;
      cin >> shift;
      shift %= m;
      if (shift == 0) continue;
      modify(1, 0, n - 1, pos[v], fin[v], shift);
    } else {
      res.reset();
      get(1, 0, n - 1, pos[v], fin[v]);
      int ans = int((res & primes).count());
      cout << ans << endl;
    }
  }

#ifdef LOCAL_HOST
  printf("TIME: %.3lf\n", double(clock()) / CLOCKS_PER_SEC);
#endif

  return 0;
}


#include <assert.h>
#include <memory.h>
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

#define pb push_back
#define INF 1011111111
#define FOR(i, a, b) for (int _n(b), i(a); i < _n; i++)
#define rep(i, n) FOR(i, 0, n)
#define CL(a, v) memset((a), (v), sizeof(a))
#define mp make_pair
#define X first
#define Y second
#define all(c) (c).begin(), (c).end()
#define SORT(c) sort(all(c))

typedef long long ll;
typedef vector<int> VI;
typedef pair<int, int> pii;

/*** TEMPLATE CODE ENDS HERE */

const int N = 1e5 + 10;
VI g[N];
int a[N], pos[N], fin[N], w[N], kw;

void dfs(int v, int from) {
  pos[v] = kw;
  w[kw++] = v;
  for (int to : g[v]) {
    if (to != from) {
      dfs(to, v);
    }
  }
  fin[v] = kw - 1;
}

const int M = 1000;
int m;
bitset<M> tree[4 * N];
int shift[4 * N];
bitset<M> al;

void build(int x, int l, int r) {
  shift[x] = 0;
  if (l == r) {
    tree[x] = bitset<M>();
    tree[x].set(a[w[l]]);
    return;
  }
  int y = (l + r) >> 1;
  build(x + x, l, y);
  build(x + x + 1, y + 1, r);
  tree[x] = tree[x + x] | tree[x + x + 1];
}

inline void apply(bitset<M> &b, int sh) {
  b = ((b << sh) & al) | (b >> (m - sh));
}

inline void push(int x) {
  if (shift[x] != 0) {
    shift[x + x] += shift[x];
    if (shift[x + x] >= m) {
      shift[x + x] -= m;
    }
    shift[x + x + 1] += shift[x];
    if (shift[x + x + 1] >= m) {
      shift[x + x + 1] -= m;
    }
    apply(tree[x + x], shift[x]);
    apply(tree[x + x + 1], shift[x]);
    shift[x] = 0;
  }
}

inline void gather(int x) { tree[x] = tree[x + x] | tree[x + x + 1]; }

void modify(int x, int l, int r, int ll, int rr, int sh) {
  if (ll <= l && r <= rr) {
    apply(tree[x], sh);
    shift[x] += sh;
    if (shift[x] >= m) {
      shift[x] -= m;
    }
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    modify(x + x, l, y, ll, rr, sh);
  }
  if (rr > y) {
    modify(x + x + 1, y + 1, r, ll, rr, sh);
  }
  gather(x);
}

bitset<M> res;

void get(int x, int l, int r, int ll, int rr) {
  if (ll <= l && r <= rr) {
    res |= tree[x];
    return;
  }
  push(x);
  int y = (l + r) >> 1;
  if (ll <= y) {
    get(x + x, l, y, ll, rr);
  }
  if (rr > y) {
    get(x + x + 1, y + 1, r, ll, rr);
  }
  gather(x);
}

int main() {
#ifdef LOCAL_HOST
  freopen("input.txt", "r", stdin);
// freopen("output.txt","w",stdout);
#endif

  ios_base::sync_with_stdio(false);

  int n;
  cin >> n >> m;
  rep(i, n) {
    cin >> a[i];
    a[i] %= m;
  }
  rep(i, n - 1) {
    int x, y;
    cin >> x >> y;
    --x, --y;
    g[x].pb(y);
    g[y].pb(x);
  }

  kw = 0;
  dfs(0, -1);
  build(1, 0, n - 1);

  bitset<M> primes;
  rep(i, m) al.set(i);

  for (int i = 2; i < m; i++) {
    bool prime = true;
    for (int j = 2; j * j <= i; j++) {
      if (i % j == 0) {
        prime = false;
        break;
      }
    }
    if (prime) {
      primes.set(i);
    }
  }

  int q;
  cin >> q;
  while (q--) {
    int op, v;
    cin >> op >> v;
    --v;
    if (op == 1) {
      int shift;
      cin >> shift;
      shift %= m;
      if (shift) {
        modify(1, 0, n - 1, pos[v], fin[v], shift);
      }
    } else {
      res.reset();
      get(1, 0, n - 1, pos[v], fin[v]);
      int ans = int((res & primes).count());
      cout << ans << endl;
    }
  }

#ifdef LOCAL_HOST
  printf("TIME: %.3lf\n", double(clock()) / CLOCKS_PER_SEC);
#endif

  return 0;
}


#include <stdio.h>
#include <vector>
#include <stack>
#include <bitset>
#include <string.h>
#define MAX 100000
#define MAXP 1000

using namespace std;

int m, tot, cp;
int inp1[MAX + 5], inp[MAX + 5], laz[MAX * 8 + 5], strt[MAX + 5], fin[MAX + 5], par[MAX + 5], ord[MAX + 5], prime[MAXP + 5];
bool ans[MAXP + 5], m1[MAXP + 5], vis[MAX + 5];
bitset<MAXP> se[MAX * 8 + 5];
vector<int> v[MAX + 5];

void rot(bitset<MAXP>* bs, int pos) {
    bitset<MAXP> tmp;
    tmp.set();
    tmp >>= (MAXP - m);
    tmp &= (*bs);
    tmp >>= (m - pos);
    (*bs) <<= pos;
    (*bs) |= tmp;
}

void init(int node, int b, int e) {
    int i;
    if (b == e) {
        se[node].set(inp1[b]);
        return;
    }
    init(2 * node, b, (b + e) / 2);
    init(2 * node + 1, (b + e) / 2 + 1, e);
    for (i = 0; i < m; i++) {
        if (se[2 * node][i] || se[2 * node + 1][i]) {
            se[node].set(i);
        }
    }
}

void update(int node, int b, int e, int i, int j, int val, int u) {
    int k;
    if (u > 0) {
        rot(&se[node], u);
        laz[node] = (laz[node] + u) % m;
    }
    if (b > j || e < i) {
        return;
    }
    if (b >= i && e <= j) {
        if (val > 0) {
            rot(&se[node], val);
            laz[node] = (laz[node] + val) % m;
        }
        return;
    }
    update(2 * node, b, (b + e) / 2, i, j, val, laz[node]);
    update(2 * node + 1, (b + e) / 2 + 1, e, i, j, val, laz[node]);
    laz[node] = 0;
    se[node].reset();
    for (k = 0; k < m; k++) {
        if (se[2 * node][k] || se[2 * node + 1][k]) {
            se[node].set(k);
        }
    }
}

void query(int node, int b, int e, int i, int j, int u) {
    int k;
    if (u > 0) {
        rot(&se[node], u);
        laz[node] = (laz[node] + u) % m;
    }
    if (b > j || e < i) {
        return;
    }
    if (b >= i && e <= j) {
        for (k = 0; k < cp; k++) {
            if (se[node][prime[k]]) {
                if (!ans[prime[k]]) {
                    ans[prime[k]] = true;
                    tot++;
                }
            }
        }
        return;
    }
    query(2 * node, b, (b + e) / 2, i, j, laz[node]);
    query(2 * node + 1, (b + e) / 2 + 1, e, i, j, laz[node]);
    laz[node] = 0;
    se[node].reset();
    for (k = 0; k < m; k++) {
        if (se[2 * node][k] || se[2 * node + 1][k]) {
            se[node].set(k);
        }
    }
}

int main() {
    int n, i, j, a, b, cnt, qu, tp, x, pre;
    scanf("%d%d", &n, &m);
    for (i = 1; i <= n; i++) {
        scanf("%d", &inp[i]);
        inp[i] %= m;
    }
    for (i = 3; i * i < m; i += 2) {
        if (m1[i]) {
            continue;
        }
        for (j = 3; i * j < m; j += 2) {
            m1[i * j] = true;
        }
    }
    cp = 0;
    if (2 < m) {
        prime[cp++] = 2;
        for (i = 3; i < m; i += 2) {
            if (!m1[i]) {
                prime[cp++] = i;
            }
        }
    }
    for (i = 0; i < n - 1; i++) {
        scanf("%d%d", &a, &b);
        v[a].push_back(b);
        v[b].push_back(a);
    }
    stack<int> st;
    cnt = 1;
    vis[1] = true;
    st.push(1);
    while (!st.empty()) {
        pre = st.top();
        strt[pre] = cnt;
        fin[pre] = cnt;
        ord[cnt++] = pre;
        st.pop();
        for (i = 0; i < v[pre].size(); i++) {
            j = v[pre][i];
            if (!vis[j]) {
                vis[j] = true;
                par[j] = pre;
                st.push(j);
            }
        }
    }
    for (i = n; i > 1; i--) {
        fin[par[ord[i]]] = max(fin[par[ord[i]]], fin[ord[i]]);
    }
    for (i = 1; i <= n; i++) {
        inp1[strt[i]] = inp[i];
    }
    init(1, 1, n);
    scanf("%d", &qu);
    while (qu--) {
        scanf("%d", &tp);
        if (tp == 1) {
            scanf("%d%d", &b, &x);
            update(1, 1, n, strt[b], fin[b], x % m, 0);
        } else {
            scanf("%d", &b);
            memset(ans, 0, sizeof(ans));
            tot = 0;
            query(1, 1, n, strt[b], fin[b], 0);
            printf("%d\n", tot);
        }
    }
    return 0;
}