#include <cstdio>
#include <cassert>
#include <vector>
#include <algorithm>

#define Nmax 200005
#define pb push_back

using namespace std;
vector<int> A[100005];

struct {
	int vecin;
	int value;
	unsigned int vect;
} dp[Nmax][25];
char letters[Nmax];
int n, m;
int tata[Nmax];
int level[Nmax];
int currentNode;

bool isSet(unsigned int X, int bit)
{
	return X & (1 << bit);
}

void changeVal (unsigned int &X, int bit)
{
	if (isSet (X, bit))
	{
		X = X & (~(1<<bit));
	} else {
		X = X | (1<<bit);
	}
}
void DFS (int nod, int lev)
{
	if (level[nod] == 0)
	{
		level[nod] = lev;
		for (int i = 0; i < A[nod].size(); i++)
			DFS (A[nod][i], lev+1);
	}
}

void update (int x, char c)
{
	level[currentNode] = level[x] + 1;
	letters[currentNode] = c;
	dp[currentNode][0].vecin = x;
	dp[currentNode][0].value = 1;
	changeVal(dp[currentNode][0].vect, c - 'a');
	for (int i = 1; i <= 20; i++)
	{
		if (dp[currentNode][i-1].vecin != 0 && dp[dp[currentNode][i-1].vecin][i-1].vecin != 0) {
			dp[currentNode][i].vecin = dp[dp[currentNode][i-1].vecin][i-1].vecin;
			dp[currentNode][i].vect = dp[currentNode][i-1].vect ^ dp[dp[currentNode][i-1].vecin][i-1].vect;
			int nr = 0;
			for (int k = 0; k < 26; k++)
				if (isSet ( dp[currentNode][i].vect, k))
				{
					nr ++;
				}
			dp[currentNode][i].value = nr;
			}
		}
	currentNode++;
}

int query (int x, int y)
{
	int levx = level[x];
	int levy = level[y];
	if (levx < levy)
	{
		swap (x, y);
		swap (levx, levy);
	}
	unsigned int dist = levx - levy;
	unsigned int rezx = 0;
	unsigned int rezy = 0;
	for (int i = 0; i <31; i++)
	{
		if (isSet (dist, i)) {
			rezx = rezx ^ dp[x][i].vect;
			x = dp[x][i].vecin;
		}
	}
	int rez = 0;
	if (x == y)
	{
		changeVal (rezx, letters[x] - 'a');
	}
	else {
		for (int i = 20; i>=0; i--)
		{
			if (dp[x][i].vecin != 0 && dp[x][i].vecin != dp[y][i].vecin)
			{
				rezx ^= dp[x][i].vect;
				rezy ^= dp[y][i].vect;
				x = dp[x][i].vecin;
				y = dp[y][i].vecin;
			}
		}
		int v = tata[x];
		rezx^= dp[x][0].vect;
		rezy^= dp[y][0].vect;
		rezx ^= rezy;
		changeVal (rezx, letters[v] - 'a');


	}
	for (int i = 0; i <26; i++)
		if (isSet(rezx, i))
			rez++;
	return rez;
}


int main()
{
	//freopen ("fis.in", "r", stdin);
	//freopen ("fis.out", "w", stdout);
	scanf ("%d %d", &n, &m);
	currentNode = n+1;
	scanf ("%s", letters+1);
	for (int i = 1; i < n; i++) {
		int x, y;
		scanf ("%d %d\n", &x, &y);
		tata[y] = x;
		A[x].pb(y);
		A[y].pb(x);
	}
	for (int i = 1; i <=n; i++)
		if (tata[i] == 0)
			DFS(i, 1);
	for (int i = 1; i <= n; i++)
	{
		if (tata[i] != 0)
		{
			dp[i][0].vecin = tata[i];
			changeVal(dp[i][0].vect, letters[i] - 'a');
			dp[i][0].value = 1;
		}
	}
	for (int j = 1; j <= 20; j++)
	{
		for (int i = 1; i <= n; i++)
		{
			if (dp[i][j-1].vecin != 0 && dp[dp[i][j-1].vecin][j-1].vecin != 0) {
				dp[i][j].vecin = dp[dp[i][j-1].vecin][j-1].vecin;
				dp[i][j].vect = dp[i][j-1].vect ^ dp[dp[i][j-1].vecin][j-1].vect;
				int nr = 0;
				for (int k = 0; k < 26; k++)
					if (isSet ( dp[i][j].vect, k))
					{
						nr ++;
					}
				dp[i][j].value = nr;
				}
		}
	}
	for (int i = 1; i <=m; i++)
	{
		int c, x, y;
		char let;
		scanf ("%d", &c);
		if (c == 1)
		{
			scanf ("%d %d", &x, &y);
			printf ("%d\n", query (x, y));
		}
		if (c == 2)
		{
			scanf ("%d %c\n", &x, &let);
			update (x, let);
		}
	}
	return 0;
}