#include <bits/stdc++.h>
using namespace std;
const int MaxN = 111111;
const int inf = 0x3fffffff;
namespace Treap {
struct node {
  int id, dep, delta, maxDep, minDep;
  int tKey, size;
  node *ch[2], *p;
  void push() {
    if (delta) {
      dep += delta;
      maxDep += delta;
      minDep += delta;
      if (ch[0]) {
        ch[0]->delta += delta;
      }
      if (ch[1]) {
        ch[1]->delta += delta;
      }
      delta = 0;
    }
  }
  void update() {
    push();
    if (ch[0]) ch[0]->push();
    if (ch[1]) ch[1]->push();
    size = ((ch[0]) ? ((ch[0])->size) : (0)) +
           ((ch[1]) ? ((ch[1])->size) : (0)) + 1;
    minDep = min(dep, min(((ch[0]) ? ((ch[0])->minDep) : (inf)),
                          ((ch[1]) ? ((ch[1])->minDep) : (inf))));
    maxDep = max(dep, max(((ch[0]) ? ((ch[0])->maxDep) : (-inf)),
                          ((ch[1]) ? ((ch[1])->maxDep) : (-inf))));
    p = 0;
    if (ch[0]) ch[0]->p = this;
    if (ch[1]) ch[1]->p = this;
  }
} treap[MaxN * 10], *buf = treap, *root = NULL;
node *alloc(int id, int dep) {
  node *x = buf++;
  x->id = id;
  x->dep = x->maxDep = x->minDep = dep;
  x->tKey = ((int)rand()) * ((int)rand());
  x->size = 1;
  x->p = x->ch[0] = x->ch[1] = NULL;
  x->delta = 0;
  return x;
}
node *merge(node *x, node *y) {
  if (x) x->push();
  if (y) y->push();
  if (!x) return y;
  if (!y) return x;
  if (x->tKey > y->tKey) {
    x->ch[1] = merge(x->ch[1], y);
    x->update();
    return x;
  } else {
    y->ch[0] = merge(x, y->ch[0]);
    y->update();
    return y;
  }
  return NULL;
}
struct Double {
  node *x, *y;
  Double(node *x = 0, node *y = 0) : x(x), y(y) {}
};
Double split(node *v, int s) {
  if (!v) return Double(0, 0);
  v->push();
  Double d;
  if (((v->ch[0]) ? ((v->ch[0])->size) : (0)) + 1 <= s) {
    d = split(v->ch[1], s - ((v->ch[0]) ? ((v->ch[0])->size) : (0)) - 1);
    v->ch[1] = d.x;
    d.x = v;
  } else {
    d = split(v->ch[0], s);
    v->ch[0] = d.y;
    d.y = v;
  }
  v->update();
  return d;
}
int GetNum(node *v) {
  int s = ((v->ch[0]) ? ((v->ch[0])->size) : (0)) + 1;
  while (v->p) {
    node *pv = v->p;
    if (v == pv->ch[1]) {
      s += ((pv->ch[0]) ? ((pv->ch[0])->size) : (0)) + 1;
    }
    v = pv;
  }
  return s;
}
int GetMin(int x, int y) {
  Double a, b;
  int oSum = root->size;
  a = split(root, y);
  b = split(a.x, x - 1);
  int ans = b.y->minDep;
  root = merge(b.x, merge(b.y, a.y));
  return ans;
}
int GetDep(node *v, int s) {
  v->push();
  if (((v->ch[0]) ? ((v->ch[0])->size) : (0)) + 1 == s) {
    return v->dep;
  }
  if (((v->ch[0]) ? ((v->ch[0])->size) : (0)) + 1 > s) {
    return GetDep(v->ch[0], s);
  }
  return GetDep(v->ch[1], s - ((v->ch[0]) ? ((v->ch[0])->size) : (0)) - 1);
}
node *addback(node *x) {
  root = merge(root, x);
  return x;
}
};  // namespace Treap
vector<int> G[MaxN];
Treap::node *L[MaxN], *R[MaxN];
void dfs(int cur, int dep) {
  L[cur] = Treap::addback(Treap::alloc(cur, dep));
  for (int i = 0; i < G[cur].size(); i++) {
    dfs(G[cur][i], dep + 1);
    Treap::addback(Treap::alloc(cur, dep));
  }
  R[cur] = Treap::addback(Treap::alloc(cur, dep));
}
int queryK(Treap::node *v, int k) {
  if (!v) return 0;
  v->push();
  if (v->dep == k) {
    int r = queryK(v->ch[1], k);
    if (r == 0) r = v->id;
    return r;
  }
  if (v->ch[1]) {
    v->ch[1]->push();
    if (v->ch[1]->minDep <= k && v->ch[1]->maxDep >= k)
      return queryK(v->ch[1], k);
  }
  return queryK(v->ch[0], k);
}
void Move(int v, int h) {
  int y = Treap::GetDep(Treap::root, Treap::GetNum(L[v]));
  Treap::Double a = Treap::split(Treap::root, Treap::GetNum(L[v]) - 1);
  int pv = queryK(a.x, y - h);
  Treap::Double b = Treap::split(a.y, Treap::GetNum(R[v]));
  b.x->delta -= (h - 1);
  b.x->push();
  Treap::root = Treap::merge(a.x, b.y);
  Treap::Double c = Treap::split(Treap::root, Treap::GetNum(R[pv]) - 1);
  Treap::node *s = Treap::alloc(pv, y - h);
  Treap::node *p = Treap::merge(b.x, s);
  Treap::root = Treap::merge(c.x, Treap::merge(p, c.y));
}
int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; i++) {
    int l;
    scanf("%d", &l);
    for (int j = 0; j < l; j++) {
      int y;
      scanf("%d", &y);
      G[i].push_back(y);
    }
  }
  dfs(1, 0);
  while (m--) {
    int t;
    scanf("%d", &t);
    if (t == 1) {
      int a, b;
      scanf("%d%d", &a, &b);
      a = Treap::GetNum(L[a]), b = Treap::GetNum(L[b]);
      if (a > b) swap(a, b);
      int r = Treap::GetMin(a, b);
      printf("%d\n", Treap::GetDep(Treap::root, a) +
                         Treap::GetDep(Treap::root, b) - 2 * r);
    }
    if (t == 2) {
      int v, h;
      scanf("%d%d", &v, &h);
      Move(v, h);
    }
    if (t == 3) {
      int k;
      scanf("%d", &k);
      printf("%d\n", queryK(Treap::root, k));
    }
  }
  return 0;
}
