#ifdef ONLINE_JUDGE #include #else #include #include #include #include #include #include #include #include #include #include #include #include #include #endif using namespace std; // lambda : [] (int a, int b) -> bool { body return } // string r_str = R"(raw string)" #define mp make_pair #define eb emplace_back #define pb push_back #define LL long long #define ULL unsigned long long #define BASE 73 #define NMAX 10000 #define NMAX2 20001 #define MOD1 1000000007 #define ALL(V) (V).begin(), (V).end() #define ALLR(V) (V).rbegin(), (V).rend() #define CRLINE Duxar(__LINE__); #define SHOWME(x) cerr << __LINE__ << ": " << #x << " = " << (x) << endl; #define ENTER putchar('\n'); int dx4[] = {-1, 0, 1, 0}; int dy4[] = {0, 1, 0, -1}; int dx6[] = {-1, -1, 0, 1, 1, 1, 0, -1}; int dy6[] = {0, 1, 1, 1, 0, -1, -1, -1}; void Duxar(int _this_line) { #ifndef ONLINE_JUDGE printf("\n . . . . . . . . . . . . . Passed line - %d\n", _this_line); #endif } template void ReadNo(T &_value) { T _sign = 1; char ch; _value = 0; while(!isdigit(ch = getchar())) { (ch == '-') && (_sign = -1); } do { _value = _value * 10 + (ch - '0'); } while(isdigit(ch = getchar())); _value *= _sign; } template void AddNr(T &a, T b) { a = a + b; while (a >= MOD1) { a -= MOD1; } while (a < 0) { a += MOD1; } } int N, M, pos_node = 1; vector values, partial_values, p2, first_found, euler_dfs, level; vector > queries; vector > rmq, graph; void DFSValues(int iam, int from); void DFSEuler(int iam, int from, int node_level); void PrepareRMQ(); int main(){ #ifndef ONLINE_JUDGE // freopen("", "r", stdin); #endif int i, x, y, t, px, py, k, dif, ans; char c; scanf("%d %d\n", &N, &M); values.resize(N + 1); graph.resize(N + 1); for (i = 1; i <= N; ++i) { scanf("%c", &c); values[i] = 1 << (c - 'a'); } scanf("\n"); for (i = 1; i < N; ++i) { ReadNo(x); ReadNo(y); graph[x].pb(y); graph[y].pb(x); } for (i = 1; i <= M; ++i) { scanf("%d", &t); if (t == 1) { scanf("%d %d\n", &x, &y); queries.pb({x, y}); } else { scanf("%d %c\n", &x, &c); ++N; values.pb(1 << (c - 'a')); graph.pb(vector ()); graph[N].pb(x); graph[x].pb(N); } } first_found.resize(N + 1); level.resize(N * 2); euler_dfs.resize(N * 2); partial_values.resize(N + 1); DFSValues(1, -1); DFSEuler(1, -1, 0); PrepareRMQ(); for (auto qr: queries) { x = qr.first; y = qr.second; px = first_found[x]; py = first_found[y]; if (py < px) { swap (py, px); } dif = py - px + 1; k = p2[dif]; ans = rmq[k][px]; if (ans > level[rmq[k][py - (1 << k) + 1]]) { ans = rmq[k][py - (1 << k) + 1]; } ans = euler_dfs[ans]; // cout << ans ; ENTER ans = partial_values[x] ^ partial_values[y] ^ values[ans]; int nr = 0; while (ans) { nr += ans & 1; ans >>= 1; } printf("%d\n", nr); } return 0; } void DFSValues(int iam, int from) { partial_values[iam] ^= values[iam]; for (auto to: graph[iam]) { if (to != from) { partial_values[to] ^= partial_values[iam]; DFSValues(to, iam); } } } void DFSEuler(int iam, int from, int node_level) { first_found[iam] = pos_node; level[pos_node] = node_level; euler_dfs[pos_node] = iam; ++pos_node; for (auto to: graph[iam]) { if (to != from) { DFSEuler(to, iam, node_level + 1); level[pos_node] = node_level; euler_dfs[pos_node] = iam; ++pos_node; } } } void PrepareRMQ() { int i, k; --pos_node; rmq.resize(20, vector (pos_node + 1)); p2.resize(pos_node + 1); rmq[0][1] = 1; for (i = 2; i <= pos_node; ++i) { rmq[0][i] = i; p2[i] = p2[i >> 1] + 1; } for (k = 1; (1 << k) <= pos_node; ++k) { int dif = 1 << (k - 1); for (i = 1; i + (1 << k) - 1 <= pos_node; ++i) { rmq[k][i] = rmq[k - 1][i]; if (level[rmq[k][i]] > level[rmq[k - 1][i + dif]]) { rmq[k][i] = rmq[k - 1][i + dif]; } } } }