#include <bits/stdc++.h>
using namespace std;
template <typename T, typename U>
inline void smin(T &a, const U &b) {
  if (a > b) a = b;
}
template <typename T, typename U>
inline void smax(T &a, const U &b) {
  if (a < b) a = b;
}
template <class T>
inline void gn(T &first) {
  char c, sg = 0;
  while (c = getchar(), (c > '9' || c < '0') && c != '-')
    ;
  for ((c == '-' ? sg = 1, c = getchar() : 0), first = 0; c >= '0' && c <= '9';
       c = getchar())
    first = (first << 1) + (first << 3) + c - '0';
  if (sg) first = -first;
}
template <class T1, class T2>
inline void gn(T1 &x1, T2 &x2) {
  gn(x1), gn(x2);
}
int power(int a, int b, int m, int ans = 1) {
  for (; b; b >>= 1, a = 1LL * a * a % m)
    if (b & 1) ans = 1LL * ans * a % m;
  return ans;
}
int son[200200][2], pa[200200], sz[200200];
int up[200200];
int val[200200], mn[200200], mx[200200];
int cur, root;
int newnode(int v) {
  int first = ++cur;
  val[first] = mn[first] = v;
  sz[first] = 1;
  up[first] = 0;
  return first;
}
void push_up(int first) {
  if (!first) return;
  mn[first] = mx[first] = val[first];
  if (son[first][0])
    smin(mn[first], mn[son[first][0]]), smax(mx[first], mx[son[first][0]]);
  if (son[first][1])
    smin(mn[first], mn[son[first][1]]), smax(mx[first], mx[son[first][1]]);
  sz[first] = 1 + sz[son[first][0]] + sz[son[first][1]];
}
void init() {
  cur = 0;
  int first = newnode(0);
  int second = newnode(0);
  son[first][1] = second;
  pa[second] = first;
  push_up(first);
  root = first;
}
int find(int first, int k) {
  if (sz[son[first][0]] >= k) return find(son[first][0], k);
  if (sz[son[first][0]] + 1 == k) return first;
  return find(son[first][1], k - sz[son[first][0]] - 1);
}
void add_up(int first, int v) {
  if (!first) return;
  up[first] += v;
  mn[first] += v;
  mx[first] += v;
  val[first] += v;
}
void push_down(int first) {
  if (up[first]) {
    add_up(son[first][0], up[first]);
    add_up(son[first][1], up[first]);
    up[first] = 0;
  }
}
int stk[200200], top;
void down(int first) {
  while (first) stk[++top] = first, first = pa[first];
  while (top) push_down(stk[top--]);
}
void rot(int first, int d) {
  int second = pa[first], z = pa[second];
  son[second][!d] = son[first][d];
  pa[son[first][d]] = second;
  pa[first] = pa[second];
  if (son[z][0] == second)
    son[z][0] = first;
  else if (son[z][1] == second)
    son[z][1] = first;
  pa[second] = first;
  son[first][d] = second;
  push_up(second);
}
void splay(int first, int g) {
  down(first);
  while (pa[first] != g) {
    if (pa[pa[first]] == g)
      rot(first, son[pa[first]][0] == first);
    else {
      int second = pa[first], z = pa[second];
      int d = (son[z][0] == second);
      son[second][d] == first ? rot(first, !d) : rot(second, d);
      rot(first, d);
    }
  }
  push_up(first);
  if (g == 0) root = first, pa[first] = 0;
}
int insert(int k, int v) {
  int first = newnode(v);
  int second = find(root, k);
  int z = find(root, k + 1);
  splay(second, 0);
  splay(z, second);
  son[z][0] = first;
  pa[first] = z;
  push_up(z);
  push_up(second);
  return first;
}
int pre(int first) {
  splay(first, 0);
  for (first = son[first][0]; son[first][1]; first = son[first][1])
    ;
  return first;
}
int nxt(int first) {
  splay(first, 0);
  for (first = son[first][1]; son[first][0]; first = son[first][0])
    ;
  return first;
}
void print(int first) {
  if (!first) return;
  push_down(first);
  printf("(%d-%d ->%d %d)", first, val[first], son[first][0], son[first][1]);
  print(son[first][0]);
  print(son[first][1]);
}
vector<int> adj[200200];
int L[200200], R[200200], id[200200];
int dep[200200], seq[200200], nn;
void dfs(int u) {
  seq[nn++] = u;
  for (int v : adj[u]) {
    dep[v] = dep[u] + 1;
    dfs(v);
  }
  seq[nn++] = u;
}
int Find(int first, int k) {
  push_down(first);
  if (son[first][1] && mn[son[first][1]] <= k && k <= mx[son[first][1]])
    return Find(son[first][1], k);
  if (val[first] == k) return first;
  return Find(son[first][0], k);
}
int main() {
  int n, m;
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    int k, u;
    gn(k);
    while (k--) gn(u), adj[i].push_back(u);
  }
  init();
  dfs(1);
  for (int i = 0; i < nn; i++) {
    int u = seq[i];
    int node = insert(i + 1, dep[u]);
    id[node] = u;
    if (L[u])
      R[u] = node;
    else
      L[u] = node;
  }
  int tp, u, v, h;
  while (m--) {
    gn(tp);
    if (tp == 1) {
      gn(u, v);
      splay(L[u], 0);
      int l = sz[son[root][0]] + 1;
      int du = val[L[u]];
      splay(L[v], 0);
      int r = sz[son[root][0]] + 1;
      int dv = val[L[v]];
      if (l > r) swap(l, r);
      int first = find(root, l);
      int second = find(root, r + 1);
      splay(first, 0);
      splay(second, first);
      printf("%d\n", du + dv - 2 * (min(min(du, dv), mn[son[second][0]] - 1)));
    } else if (tp == 2) {
      gn(u, h);
      int rgt = nxt(R[u]);
      int lft = pre(L[u]);
      splay(L[u], 0);
      int dp = val[L[u]] - h;
      v = id[Find(son[L[u]][0], dp)];
      splay(lft, 0);
      splay(rgt, lft);
      int mv = son[rgt][0];
      son[rgt][0] = 0;
      push_up(rgt);
      push_up(lft);
      add_up(mv, -(h - 1));
      int tar = R[v];
      int ptar = pre(tar);
      splay(ptar, 0);
      splay(tar, ptar);
      son[tar][0] = mv;
      pa[mv] = tar;
      push_up(tar);
      push_up(ptar);
    } else {
      gn(h);
      splay(1, 0);
      splay(2, 1);
      printf("%d\n", id[Find(son[2][0], h)]);
    }
  }
  return 0;
}
