#include <bits/stdc++.h>
#pragma GCC optimize(3)
using namespace std;
template <typename T>
inline bool chkmin(T &x, T y) {
  return x > y ? x = y, 1 : 0;
}
template <typename T>
inline bool chkmax(T &x, T y) {
  return x < y ? x = y, 1 : 0;
}
template <typename T>
inline void read(T &x) {
  char ch = getchar();
  int f = 1;
  x = 0;
  while (ch < '0' || ch > '9') {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
  x *= f;
}
template <typename T, typename... Args>
inline void read(T &x, Args &...args) {
  char ch = getchar();
  int f = 1;
  x = 0;
  while (ch < '0' || ch > '9') {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
  x *= f;
  read(args...);
}
int n, m, st[200050], en[200050];
int ver[200050 * 2], size[200050 * 2], tag[200050 * 2], ch[200050 * 2][2],
    fa[200050 * 2], dep[200050 * 2], maxd[200050 * 2], mind[200050 * 2], rt,
    tcnt;
vector<int> adj[200050];
inline int rnd() {
  static int x = 19260817;
  return x = (x * 48271ll) & INT_MAX;
}
inline void put_tag(int u, int w) {
  if (u) tag[u] += w, maxd[u] += w, mind[u] += w, dep[u] += w;
}
inline void push(int u) {
  if (tag[u]) put_tag(ch[u][0], tag[u]), put_tag(ch[u][1], tag[u]), tag[u] = 0;
}
inline void update(int u) {
  size[u] = size[ch[u][0]] + size[ch[u][1]] + 1;
  maxd[u] = mind[u] = dep[u];
  chkmax(maxd[u], max(maxd[ch[u][0]], maxd[ch[u][1]]));
  chkmin(mind[u], min(mind[ch[u][0]], mind[ch[u][1]]));
}
int merge(int x, int y) {
  if (!x || !y) return x ^ y;
  push(x), push(y);
  int t;
  if (rnd() % (size[x] + size[y]) < size[x])
    t = x, fa[ch[x][1] = merge(ch[x][1], y)] = x;
  else
    t = y, fa[ch[y][0] = merge(x, ch[y][0])] = y;
  return update(t), t;
}
void split(int u, int k, int &x, int &y) {
  if (!u)
    x = y = 0;
  else {
    push(u);
    if (k <= size[ch[u][0]])
      split(ch[u][0], k, x, ch[u][0]), fa[x] = 0, y = fa[ch[u][0]] = u;
    else
      split(ch[u][1], k - size[ch[u][0]] - 1, ch[u][1], y),
          fa[y] = 0, x = fa[ch[u][1]] = u;
    update(u);
  }
}
inline int rnk(int u) {
  int ret = size[ch[u][0]];
  while (u)
    ret += (!fa[u] || u == ch[fa[u]][1]) * (size[ch[fa[u]][0]] + 1), u = fa[u];
  return ret;
}
inline int create(int v, int w) {
  int u = ++tcnt;
  ver[u] = v, dep[u] = maxd[u] = mind[u] = w, size[u] = 1;
  return u;
}
inline void dfs(int u, int fa, int d) {
  rt = merge(rt, st[u] = create(u, d));
  for (auto v : adj[u])
    if (v != fa) dfs(v, u, d + 1);
  rt = merge(rt, en[u] = create(u, d));
}
inline int get(int u, int d) {
  push(u);
  if (mind[ch[u][1]] <= d && d <= maxd[ch[u][1]]) return get(ch[u][1], d);
  if (dep[u] == d) return ver[u];
  return get(ch[u][0], d);
}
inline int getd(int u) {
  int x, y, z, ret;
  split(rt, rnk(st[u]), x, z), split(x, rnk(st[u]) - 1, x, y);
  ret = dep[y], rt = merge(x, merge(y, z));
  return ret;
}
int main() {
  maxd[0] = -1e9, mind[0] = 1e9;
  read(n, m);
  int op, u, v, x, y, z, t;
  for (register int i = 1; i <= n; ++i) {
    read(op);
    while (op--) read(u), adj[i].push_back(u);
  }
  dfs(1, 0, 1);
  while (m--) {
    read(op);
    if (op == 1) {
      read(u, v);
      if (u == v) {
        puts("0");
        continue;
      }
      int res = getd(u) + getd(v);
      if (rnk(st[u]) > rnk(st[v])) swap(u, v);
      split(rt, rnk(en[v]) - 1, x, z), split(x, rnk(st[u]), x, y);
      printf("%d\n", res - 2 * (mind[y] - 1));
      rt = merge(merge(x, y), z);
    } else if (op == 2) {
      read(u, v);
      int want = getd(u) - v;
      split(rt, rnk(st[u]), x, y), t = get(x, want), rt = merge(x, y);
      split(rt, rnk(en[u]), x, z), split(x, rnk(st[u]) - 1, x, y),
          put_tag(y, -v + 1), rt = merge(x, z);
      split(rt, rnk(en[t]) - 1, x, z), rt = merge(x, merge(y, z));
    } else
      read(u), printf("%d\n", get(rt, ++u));
  }
  return 0;
}
