#include <bits/stdc++.h>
template <class T>
inline bool chkmn(T &a, const T &b) {
  return a > b ? a = b, 1 : 0;
}
template <class T>
inline bool chkmx(T &a, const T &b) {
  return a < b ? a = b, 1 : 0;
}
using std::make_pair;
using std::pair;
using std::swap;
using std::vector;
const int INF = 0x1f1f1f1f, MAXN = 1e5 + 11;
namespace Splay {
const int SIZE = MAXN << 2;
struct Node {
  Node *son[2], *fa;
  int add, ssz, isz;
  pair<int, int> self, imin, imax;
  Node() {
    imin = make_pair(INF, 0);
    imax = make_pair(-INF, 0);
    son[0] = son[1] = fa = 0;
    add = isz = ssz = 0;
  }
  bool kind() { return fa->son[1] == this; }
  bool isRoot() { return fa->son[0] != this && fa->son[1] != this; }
  void Add(int);
  void up();
  void down() {
    if (add) {
      son[0]->Add(add);
      son[1]->Add(add);
      add = 0;
    }
  }
  void uptoroot() {
    up();
    if (!isRoot()) fa->uptoroot();
  }
} *POOL = (Node *)malloc(SIZE * sizeof(Node)), *ME = POOL,
  *null = new (ME++) Node, *root = null, *lnull, *rnull;
void Node::Add(int v) {
  if (this != null) {
    add += v;
    self.first += v;
    imin.first += v;
    imax.first += v;
  }
}
void Node::up() {
  assert(this != null);
  if (this == lnull || this == rnull)
    imin = make_pair(INF, 0), imax = make_pair(-INF, 0);
  else
    imin = imax = self;
  chkmn(imin, min(son[0]->imin, son[1]->imin));
  chkmx(imax, max(son[0]->imax, son[1]->imax));
  isz = ssz + son[0]->isz + son[1]->isz;
}
Node *newNode(pair<int, int> v) {
  static Node *cur;
  cur = ME++;
  cur->son[0] = cur->son[1] = cur->fa = null;
  cur->imin = cur->imax = cur->self = v;
  cur->add = 0;
  cur->isz = cur->ssz = 1;
  return cur;
}
Node *Append(Node *&pos, Node *nw) {
  nw->son[0] = pos;
  if (pos != null) pos->fa = nw;
  pos = nw;
  pos->up();
  return pos;
}
void Trans(Node *pos) {
  static Node *f, *grf;
  static int d;
  f = pos->fa, grf = f->fa;
  d = pos->kind();
  f->down();
  pos->down();
  if (!f->isRoot()) grf->son[f->kind()] = pos;
  pos->fa = grf;
  f->son[d] = pos->son[!d];
  pos->son[!d]->fa = f;
  pos->son[!d] = f;
  f->fa = pos;
  f->up();
  pos->up();
  assert(pos->son[0] && pos->son[1] && f->son[0] && f->son[1]);
}
void SplayTo(Node *pos, Node *goal = 0) {
  bool flag = 0;
  if (goal == 0) goal = null, flag = 1;
  while (pos->fa != goal) {
    Node *f = pos->fa;
    if (f->fa != goal) Trans(pos->kind() == f->kind() ? f : pos);
    Trans(pos);
  }
  if (goal == null && !flag) root = pos;
}
Node *Adjace(Node *pos, int dir = 0) {
  SplayTo(pos, null);
  pos = pos->son[dir];
  while (pos->son[!dir] != null) pos = pos->son[!dir];
  SplayTo(pos, null);
  return pos;
}
Node *Split(Node *p1, Node *p2) {
  p1 = Adjace(p1, 0);
  p2 = Adjace(p2, 1);
  SplayTo(p1, null);
  SplayTo(p2, p1);
  return p2->son[0];
}
int Rank(Node *pos) {
  SplayTo(pos, null);
  return pos->son[0]->isz;
}
}  // namespace Splay
using namespace Splay;
vector<int> son[MAXN];
struct SubTree {
  Splay::Node *lbound, *rbound, *trfa;
} sub[MAXN];
void out(Splay::Node *pos, int tab = 0) {
  if (pos == null) return;
  out(pos->son[0], tab + 1);
  for (int i = 1; i <= tab; ++i) printf("  ");
  printf("|id=%d v=%d add=%d imin=(%d,%d) imax=(%d,%d) %x\n", pos->self.second,
         pos->self.first, pos->add, pos->imin.first, pos->imin.second,
         pos->imax.first, pos->imax.second, pos);
  out(pos->son[1], tab + 1);
}
void print() {
  printf("%s", "|--begin--\n");
  out(root);
  printf("%s", "\n|--end----\n");
}
void ppa(Splay::Node *pos) {
  if (pos == null) return;
  printf("%d add=%d  ", pos->self.second, pos->add);
  ppa(pos->fa);
}
void printpath(Splay::Node *pos) {
  printf("%s", "#\n#");
  ppa(pos);
  printf("%s", "\n#\n");
}
void DFS(int pos, int dep, Splay::Node *&s) {
  sub[pos].lbound = Append(s, newNode(make_pair(dep, pos)));
  for (typeof((son[pos]).begin()) it = (son[pos]).begin();
       it != (son[pos]).end(); ++it) {
    Append(s, newNode(make_pair(dep, pos)));
    sub[*it].trfa = s;
    DFS(*it, dep + 1, s);
  }
  sub[pos].rbound = Append(s, newNode(make_pair(dep, pos)));
}
int FindPar(int p, int acn) {
  SplayTo(sub[p].lbound, null);
  Splay::Node *pos = root->son[0];
  int dep = root->self.first - acn;
  for (;;) {
    pos->down();
    if (pos->son[1]->imin.first <= dep && dep <= pos->son[1]->imax.first)
      pos = pos->son[1];
    else if (pos->self.first == dep)
      return pos->self.second;
    else
      pos = pos->son[0];
  }
}
void Move(int pos, int acn) {
  int par = FindPar(pos, acn);
  Splay::Node *rt = Split(sub[pos].trfa, sub[pos].rbound);
  rt->fa->son[0] = null, rt->fa->uptoroot();
  rt->fa = null;
  SplayTo(sub[pos].trfa);
  assert(sub[pos].trfa != lnull && sub[pos].trfa != rnull);
  sub[pos].trfa->self.second = par;
  sub[pos].trfa->up();
  sub[pos].trfa->Add(1 - acn);
  Splay::Node *last = Adjace(sub[par].rbound, 0);
  SplayTo(last, null);
  SplayTo(sub[par].rbound, last);
  if (sub[par].rbound->son[0] != null) {
    assert(sub[par].rbound->son[0] == null);
  }
  sub[par].rbound->son[0] = sub[pos].trfa;
  sub[par].rbound->uptoroot();
  sub[pos].trfa->fa = sub[par].rbound;
}
int Dist(int p1, int p2) {
  if (Rank(sub[p1].lbound) > Rank(sub[p2].lbound)) swap(p1, p2);
  Splay::Node *rt = Split(sub[p1].lbound, sub[p2].lbound);
  return sub[p1].lbound->self.first + sub[p2].lbound->self.first -
         2 * rt->imin.first;
}
int DepLast(int dep) {
  ++dep;
  Splay::Node *pos = root;
  for (;;) {
    pos->down();
    if (pos->son[1]->imin.first <= dep && dep <= pos->son[1]->imax.first)
      pos = pos->son[1];
    else if (pos->self.first == dep)
      return pos->self.second;
    else
      pos = pos->son[0];
  }
}
int main() {
  int n, m;
  scanf("%d", &n), scanf("%d", &m);
  for (int i = 1; i <= n; ++i) {
    int sc;
    scanf("%d", &sc);
    for (int j = 1; j <= sc; ++j) {
      int s;
      scanf("%d", &s);
      son[i].push_back(s);
    }
  }
  root = lnull = newNode(make_pair(INF, INF));
  rnull = newNode(make_pair(INF, INF));
  ;
  DFS(1, 1, root);
  Append(root, rnull);
  for (int i = 1; i <= m; ++i) {
    int opt, v, u, h, k;
    scanf("%d", &opt);
    switch (opt) {
      case 1:
        scanf("%d", &v), scanf("%d", &u);
        printf("%d", Dist(v, u)), putchar('\n');
        break;
      case 2:
        scanf("%d", &v), scanf("%d", &h);
        Move(v, h);
        break;
      case 3:
        scanf("%d", &k);
        printf("%d", DepLast(k)), putchar('\n');
        break;
    }
  }
  return 0;
}
