#include <bits/stdc++.h>
using namespace std;
const int maxn = 500100;
int n, m;
struct Tree {
  vector<int> ver[maxn];
  int val[maxn], id[maxn], tot;
  inline void dfs(int x, int fat) {
    id[++tot] = x;
    val[tot] = 1;
    for (int i = 0; i < (int)ver[x].size(); i++) dfs(ver[x][i], x);
    id[++tot] = x + n;
    val[tot] = -1;
  }
  inline void init() {
    for (int i = 1; i <= n; i++) {
      int s, x;
      scanf("%d", &s);
      while (s--) scanf("%d", &x), ver[i].push_back(x);
    }
    dfs(1, 0);
  }
} T;
struct node {
  int sumv, minv, maxv, lval, rmax, rval;
  int Sumv, Minv, Maxv;
  node() {
    sumv = 0;
    minv = 1e9;
    maxv = -1e9;
    Sumv = 0;
    Minv = 1e9;
    Maxv = -1e9;
  }
  node(int v) {
    sumv = minv = maxv = max(v, 0);
    Sumv = Minv = Maxv = v;
    lval = rval = v;
    rmax = -1e9;
  }
};
inline node Merge(node l, node r) {
  node ans;
  ans.lval = l.lval;
  ans.rval = r.rval;
  ans.sumv = l.sumv + r.sumv;
  if (l.rval == -1) ans.sumv--;
  ans.minv = min(l.minv, r.minv + l.sumv + min(l.rval, 0));
  ans.maxv = max(l.maxv, r.maxv + l.sumv + min(l.rval, 0));
  ans.Sumv = l.Sumv + r.Sumv;
  ans.Minv = min(l.Minv, r.Minv + l.Sumv);
  ans.Maxv = max(l.Maxv, r.Maxv + l.Sumv);
  return ans;
}
struct Splay {
  int ch[maxn][2], fa[maxn], val[maxn], size[maxn], root;
  node v[maxn];
  inline void pushup(int p) {
    size[p] = size[ch[p][0]] + size[ch[p][1]] + 1;
    v[p] = Merge(v[ch[p][0]], Merge(node(val[p]), v[ch[p][1]]));
  }
  inline void rotate(int p) {
    int f = fa[p], ff = fa[f], t = (ch[f][1] == p), w = ch[p][t ^ 1];
    if (ff) ch[ff][ch[ff][1] == f] = p;
    ch[p][t ^ 1] = f;
    ch[f][t] = w;
    if (w) fa[w] = f;
    fa[f] = p;
    fa[p] = ff;
    if (!fa[p]) root = p;
    pushup(f);
    pushup(p);
  }
  inline void splay(int p, int to = 0) {
    while (fa[p] != to) {
      int f = fa[p], ff = fa[f];
      if (ff != to) rotate((ch[f][0] == p) ^ (ch[ff][0] == f) ? p : f);
      rotate(p);
    }
  }
  inline void dfs(int x, int suml) {
    if (x == 0) return;
    dfs(ch[x][0], suml);
    cout << x << ' ' << v[ch[x][0]].sumv + max(val[x], 0) + suml << ' '
         << val[x] << ' ' << ch[x][0] << ' ' << ch[x][1] << endl;
    dfs(ch[x][1], suml + v[ch[x][0]].sumv + val[x]);
  }
  int buf[maxn], id[maxn];
  inline int build(int fat, int l, int r) {
    if (l > r) return 0;
    int mid = (l + r) >> 1, res = id[mid];
    val[res] = buf[mid];
    fa[res] = fat;
    ch[res][0] = build(res, l, mid - 1);
    ch[res][1] = build(res, mid + 1, r);
    pushup(res);
    return res;
  }
  inline void init() {
    int tot = T.tot;
    for (int i = 2; i <= tot + 1; i++)
      buf[i] = T.val[i - 1], id[i] = T.id[i - 1];
    id[1] = tot + 1;
    id[tot + 2] = tot + 2;
    buf[1] = 0;
    buf[tot + 2] = 0;
    root = build(0, 1, tot + 2);
  }
  inline int getrank(int x) {
    splay(x);
    return size[ch[root][0]];
  }
  inline int getkth(int p, int k) {
    if (size[ch[p][0]] >= k) return getkth(ch[p][0], k);
    if (size[ch[p][0]] + 1 == k) return p;
    return getkth(ch[p][1], k - size[ch[p][0]] - 1);
  }
  inline void split(int l, int r) {
    int L = getkth(root, l), R = getkth(root, r + 2);
    splay(L);
    splay(R, L);
  }
  inline int getdis(int x, int y) {
    int inx = getrank(x), outx = getrank(x + n), iny = getrank(y),
        outy = getrank(y + n);
    if (inx > iny) swap(inx, iny), swap(outx, outy), swap(x, y);
    if (outy < outx) {
      split(inx, iny);
      return v[ch[ch[root][1]][0]].Sumv - 1;
    } else {
      split(outx, iny);
      node res = v[ch[ch[root][1]][0]];
      return res.Sumv - res.Minv - res.Minv;
    }
  }
  inline void Move(int x, int to) {
    int inx = getrank(x), outx = getrank(x + n);
    split(inx, outx);
    int rt = ch[ch[root][1]][0];
    ch[ch[root][1]][0] = 0;
    fa[rt] = 0;
    pushup(ch[root][1]);
    pushup(root);
    int outto = getrank(to + n);
    split(outto, outto - 1);
    fa[rt] = ch[root][1];
    ch[ch[root][1]][0] = rt;
    pushup(ch[root][1]);
    pushup(root);
  }
  inline int solve3(int k, int start = -1) {
    int now = start < 0 ? root : start, suml = 0;
    k++;
    while (now) {
      if (v[ch[now][1]].minv + val[now] + v[ch[now][0]].sumv + suml <= k &&
          v[ch[now][1]].maxv + val[now] + v[ch[now][0]].sumv + suml >= k) {
        suml += v[ch[now][0]].sumv + val[now];
        now = ch[now][1];
      } else {
        if (v[ch[now][0]].sumv + suml + max(val[now], 0) == k)
          return now > n ? now - n : now;
        now = ch[now][0];
      }
    }
    assert(0);
    return 5;
  }
  inline int getfather(int x, int h) {
    int di = getdis(x, 1);
    splay(x);
    return solve3(di - h, ch[x][0]);
  }
} S;
inline void init() {
  scanf("%d%d", &n, &m);
  T.init();
  S.init();
}
int main() {
  init();
  int u, v, h, k;
  while (m--) {
    int opt;
    scanf("%d", &opt);
    if (opt == 1) scanf("%d%d", &v, &u), printf("%d\n", S.getdis(v, u));
    if (opt == 2) scanf("%d%d", &v, &h), S.Move(v, S.getfather(v, h));
    if (opt == 3) scanf("%d", &k), printf("%d\n", S.solve3(k));
  }
  return 0;
}
