#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100000 + 10;
struct Splay_tree {
  int l, r, f, maxs[2], mins, s, v, size;
} t[MAXN * 2], empty;
int ROOT;
inline void Upd(int first) {
  t[first].s = t[t[first].l].s + t[t[first].r].s + t[first].v;
  t[first].maxs[0] = max(t[t[first].r].maxs[0],
                         t[t[first].l].maxs[0] + t[t[first].r].s + t[first].v);
  t[first].maxs[1] = max(t[t[first].r].maxs[1],
                         t[t[first].l].maxs[1] - t[t[first].r].s - t[first].v);
  t[first].mins = min(t[t[first].l].mins,
                      t[t[first].r].mins + t[t[first].l].s + t[first].v);
  t[first].size = t[t[first].l].size + t[t[first].r].size + 1;
}
inline void r_rotate(int first) {
  int f = t[first].f, l = t[first].l;
  (t[f].l == first ? (t[f].l) : (t[f].r)) = l;
  t[l].f = f;
  t[first].l = t[l].r, t[t[first].l].f = first;
  t[l].r = first, t[first].f = l;
  Upd(first);
}
inline void l_rotate(int first) {
  int f = t[first].f, r = t[first].r;
  (t[f].l == first ? (t[f].l) : (t[f].r)) = r;
  t[r].f = f;
  t[first].r = t[r].l, t[t[first].r].f = first;
  t[r].l = first, t[first].f = r;
  Upd(first);
}
inline void Splay(int first, int rootf) {
  t[0] = empty;
  for (; t[first].f != rootf;) {
    int f = t[first].f, g = t[f].f;
    if (g == rootf)
      if (t[f].l == first)
        r_rotate(f);
      else
        l_rotate(f);
    else if (t[g].l == f)
      if (t[f].l == first)
        r_rotate(g), r_rotate(f);
      else
        l_rotate(f), r_rotate(g);
    else if (t[f].r == first)
      l_rotate(g), l_rotate(f);
    else
      r_rotate(f), l_rotate(g);
  }
  Upd(first);
  if (!rootf) ROOT = first;
}
inline int Getn(int first) {
  Splay(first, 0);
  return t[t[first].l].size + 1;
}
inline int Getpre(int first) {
  for (first = t[first].l; t[first].r; first = t[first].r)
    ;
  return first;
}
inline int Getnex(int first) {
  for (first = t[first].r; t[first].l; first = t[first].l)
    ;
  return first;
}
inline int Getp(int first, int k) {
  for (;;) {
    if (t[first].l && k <= t[t[first].l].size)
      first = t[first].l;
    else if (t[t[first].l].size + 1 == k)
      return first;
    else
      k -= t[t[first].l].size + 1, first = t[first].r;
  }
}
int n, m, L[MAXN], R[MAXN], idx, pos[MAXN * 2];
vector<int> e[MAXN];
void DFS(int first) {
  L[first] = ++idx;
  pos[idx] = first;
  t[idx].maxs[0] = 1;
  t[idx].v = t[idx].s = 1;
  for (int i = 0; i < (int)e[first].size(); ++i) DFS(e[first][i]);
  R[first] = ++idx;
  pos[idx] = first;
  t[idx].v = t[idx].s = t[idx].mins = -1;
  t[idx].maxs[1] = 1;
}
void init() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; ++i) {
    int num;
    scanf("%d", &num);
    for (int j = 1, first; j <= num; ++j)
      scanf("%d", &first), e[i].push_back(first);
  }
  DFS(1);
  for (int i = 1; i < idx; ++i) t[i].r = i + 1, t[i + 1].f = i;
  Splay(idx, 0);
}
int Query(int first, int second) {
  int Lx = Getn(L[first]), Rx = Getn(R[first]), Ly = Getn(L[second]),
      Ry = Getn(R[second]);
  if (Lx > Ly) swap(first, second), swap(Lx, Ly), swap(Rx, Ry);
  Splay(L[second], 0);
  int dy = t[t[L[second]].l].s;
  Splay(L[first], 0);
  int dx = t[t[L[first]].l].s;
  if (Ry < Rx) return dy - dx;
  Splay(L[second], ROOT);
  return dx + dy - (dx + t[t[t[ROOT].r].l].mins) * 2;
}
void Print(int first) {
  if (t[first].l) Print(t[first].l);
  printf("%d %d ", pos[first], t[first].v);
  if (t[first].r) Print(t[first].r);
}
int Find(int first, int k, bool f) {
  int px = 0, s = 0, pm = 0, d = f ? -1 : 1;
  for (;;) {
    if (s + t[t[first].r].maxs[f] >= k)
      first = t[first].r;
    else if (s + t[t[first].r].s * d + t[first].v * d == k)
      return pos[first];
    else
      s += (t[t[first].r].s + t[first].v) * d, first = t[first].l;
  }
  return -1;
}
void Opr(int first, int h) {
  Splay(L[first], 0);
  int dx = t[t[L[first]].l].s;
  int second = Find(t[ROOT].l, h, 0);
  Splay(L[first], 0);
  int pl = Getpre(ROOT);
  Splay(R[first], 0);
  int pr = Getnex(ROOT);
  Splay(pl, 0);
  Splay(pr, pl);
  int px = t[pr].l;
  t[px].f = 0, t[pr].l = 0;
  Splay(pr, 0);
  Splay(R[second], 0);
  Splay(Getpre(ROOT), 0);
  t[R[second]].l = px;
  t[px].f = R[second];
  Splay(R[second], 0);
}
void solve() {
  for (int i = 1; i <= m; ++i) {
    int ty, first, second;
    scanf("%d", &ty);
    if (ty == 1)
      scanf("%d%d", &first, &second), printf("%d\n", Query(first, second));
    else if (ty == 2)
      scanf("%d%d", &first, &second), Opr(first, second);
    else
      scanf("%d", &first), printf("%d\n", Find(ROOT, first + 1, 1));
  }
}
int main() {
  init();
  solve();
  fclose(stdin);
  fclose(stdout);
  return 0;
}
