#include <bits/stdc++.h>
const int inf = 1e9;
const int N = 2e5 + 10;
using namespace std;
int x, y, n, m, opt, head[N], top, cnt, Y[N];
struct data {
  int x, y, next;
} e[N << 1];
int read() {
  int x = 0, f = 1, c = getchar();
  while (c < '0' || c > '9') {
    if (c == '-') f = -1;
    c = getchar();
  }
  while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
  return x * f;
}
struct node *null, *rt, *st[N], *ed[N];
void Insert(int x, int y) {
  e[++cnt].x = x;
  e[cnt].y = y;
  e[cnt].next = head[x];
  head[x] = cnt;
}
struct node {
  node *L, *R, *Fa;
  int val, Min, Max, mk, id, S, mark;
  void Del(int v) {
    if (this == null) return;
    val += v;
    Max += v;
    Min += v;
    mk += v;
  }
  void Down() {
    if (this == null) return;
    if (mk) {
      L->Del(mk);
      R->Del(mk);
      mk = 0;
    }
  }
  void Update() {
    if (this == null) return;
    S = L->S + R->S + 1;
    Min = Max = val;
    Min = min(Min, min(L->Min, R->Min));
    Max = max(Max, max(L->Max, R->Max));
  }
  void Zig() {
    node *y = Fa, *z = y->Fa;
    if (z->L == y)
      z->L = this;
    else
      z->R = this;
    Fa = z;
    y->L = R;
    if (R != null) R->Fa = y;
    y->Fa = this;
    R = y;
    y->Update();
  }
  void Zag() {
    node *y = Fa, *z = y->Fa;
    if (z->L == y)
      z->L = this;
    else
      z->R = this;
    Fa = z;
    y->R = L;
    if (L != null) L->Fa = y;
    y->Fa = this;
    L = y;
    y->Update();
  }
} Nd[N];
void Splay(node *x, node *Aim) {
  static node *S[N];
  node *tmp = x;
  int k = 0;
  while (tmp->Fa != Aim) {
    S[++k] = tmp;
    tmp = tmp->Fa;
  }
  S[++k] = tmp;
  while (k) S[k--]->Down();
  while (x->Fa != Aim) {
    node *y = x->Fa, *z = y->Fa;
    if (z != Aim)
      if (y->L == x)
        if (z->L == y)
          y->Zig(), x->Zig();
        else
          x->Zig(), x->Zag();
      else if (z->R == y)
        y->Zag(), x->Zag();
      else
        x->Zag(), x->Zig();
    else if (y->L == x)
      x->Zig();
    else
      x->Zag();
  }
  x->Update();
  if (Aim == null) rt = x;
}
node *find(node *x, int k) {
  x->Down();
  if (x->L->S + 1 == k) return x;
  return x->L->S + 1 > k ? find(x->L, k) : find(x->R, k - x->L->S - 1);
}
void dfs(int x, int deep) {
  st[x] = Nd + (++top);
  st[x]->id = x;
  for (int i = head[x]; i; i = e[i].next) dfs(e[i].y, deep + 1);
  ed[x] = Nd + (++top);
  ed[x]->id = x;
  st[x]->val = ed[x]->val = deep;
}
void Build(int L, int R, node *fa, int f) {
  if (L > R) return;
  int mid = (L + R) >> 1;
  node *t = Nd + mid;
  t->Fa = fa;
  if (fa != null)
    if (!f)
      fa->L = t;
    else
      fa->R = t;
  else
    rt = t;
  Build(L, mid - 1, t, 0);
  Build(mid + 1, R, t, 1);
  t->Update();
}
int Find(node *x, int k) {
  x->Down();
  if (x->R->Min <= k && k <= x->R->Max) return Find(x->R, k);
  if (x->val == k) return x->id;
  return Find(x->L, k);
}
int Dis(int x, int y) {
  node *u = st[x], *v = st[y];
  Splay(u, null);
  int su = rt->L->S;
  Splay(v, null);
  int sv = rt->L->S;
  if (su > sv) swap(u, v);
  Splay(u, null);
  Splay(v, rt);
  node *w = rt->R->L;
  return u->val + v->val - 2 * min(min(u->val, v->val), w->Min - 1);
}
int GetFather(int x, int h) {
  node *u = st[x];
  Splay(u, null);
  return Find(u->L, u->val - h);
}
void SetFather(int x, int f) {
  Splay(st[x], null);
  node *pre = find(rt, rt->L->S);
  Splay(ed[x], null);
  node *nxt = find(rt, rt->L->S + 2);
  Splay(pre, null);
  Splay(nxt, rt);
  node *w = rt->R->L;
  w->Del(st[f]->val - st[x]->val + 1);
  w->Fa = rt->R->L = null;
  rt->R->Update();
  rt->Update();
  Splay(ed[f], null);
  pre = find(rt, rt->L->S);
  Splay(pre, null);
  Splay(ed[f], rt);
  rt->R->L = w;
  w->Fa = rt->R;
  rt->R->Update();
  rt->Update();
}
void print(node *x) {
  if (x == null) return;
  print(x->L);
  printf("Id=%d val=%d Fa=%d v=%d mk=%d min=%d max=%d\n", x->mark, x->id,
         x->Fa->mark, x->val, x->mk, x->Min, x->Max);
  print(x->R);
}
int main() {
  null = Nd;
  for (int i = 0; i < N; i++)
    Nd[i] = (node){null, null, null, 0, inf, 0, 0, 0, 1, i};
  null->S = 0;
  n = read();
  m = read();
  for (int i = 1; i <= n; i++) {
    x = read();
    for (int j = 1; j <= x; j++) Y[j] = read();
    for (int j = x; j; j--) Insert(i, Y[j]);
  }
  Nd[++top].val = 0;
  dfs(1, 1);
  Nd[++top].val = 0;
  Build(1, top, null, 0);
  for (int i = 1; i <= m; i++) {
    opt = read();
    if (opt == 1) {
      x = read();
      y = read();
      printf("%d\n", Dis(x, y));
    }
    if (opt == 2) {
      x = read();
      y = read();
      SetFather(x, GetFather(x, y));
    }
    if (opt == 3) {
      x = read();
      printf("%d\n", Find(rt, x + 1));
    }
  }
}
