#include <bits/stdc++.h>
const int mod = 998244353, N = 5e5 + 10, INF = 0x3f3f3f3f;
const double eps = 1e-9, alpha = 0.7;
template <typename T>
inline T read() {
  T x = 0;
  bool f = 0;
  char ch = getchar();
  while (!isdigit(ch)) {
    f = ch == '-';
    ch = getchar();
  }
  while (isdigit(ch)) {
    x = x * 10 + ch - '0';
    ch = getchar();
  }
  return f ? -x : x;
}
template <typename T>
inline T max(const T &x, const T &y) {
  return x > y ? x : y;
}
template <typename T>
inline T min(const T &x, const T &y) {
  return x < y ? x : y;
}
template <typename T>
inline T abs(const T &x) {
  return x > 0 ? x : -x;
}
inline int Mod(int x) {
  if (x >= mod) {
    return x - mod;
  } else if (x < 0) {
    return x + mod;
  } else {
    return x;
  }
}
template <typename T1, typename T2>
struct pair {
  T1 first;
  T2 second;
  pair(const T1 &x = 0, const T2 &y = 0) {
    first = x;
    second = y;
  }
  friend pair operator+(const pair<T1, T2> &x, const pair<T1, T2> &y) {
    return pair(x.first + y.first, x.second + y.second);
  }
  friend pair operator-(const pair<T1, T2> &x, const pair<T1, T2> &y) {
    return pair(x.first - y.first, x.second - y.second);
  }
  friend bool operator<(const pair<T1, T2> &x, const pair<T1, T2> &y) {
    return x.first < y.first || (x.first == y.first && x.second < y.second);
  }
  friend bool operator<=(const pair<T1, T2> &x, const pair<T1, T2> &y) {
    return x.first < y.first || (x.first == y.first && x.second <= y.second);
  }
  friend bool operator>(const pair<T1, T2> &x, const pair<T1, T2> &y) {
    return x.first > y.first || (x.first == y.first && x.second > y.second);
  }
  friend bool operator>=(const pair<T1, T2> &x, const pair<T1, T2> &y) {
    return x.first > y.first || (x.first == y.first && x.second >= y.second);
  }
  friend bool operator==(const pair<T1, T2> &x, const pair<T1, T2> &y) {
    return x.first == y.first && x.second == y.second;
  }
  friend bool operator!=(const pair<T1, T2> &x, const pair<T1, T2> &y) {
    return x.first != y.first || x.second != y.second;
  }
};
template <typename T1, typename T2>
inline pair<T1, T2> make_pair(const T1 &x, const T2 &y) {
  return pair<T1, T2>(x, y);
}
template <typename T>
struct stack {
  int top;
  T vals[N];
  bool empty() { return !top; }
  void push(T x) { vals[++top] = x; }
  void pop() {
    if (top > 0) {
      --top;
    }
    return;
  }
  void clear() { top = 0; }
  T TOP() { return top ? vals[top] : T(-1); }
};
inline int ksm(int x, int y) {
  int ret = 1;
  for (; y; y /= 2, x = 1LL * x * x % mod) {
    if (y & 1) {
      ret = 1LL * ret * x % mod;
    }
  }
  return ret;
}
inline int ksc(int x, int y) {
  int ret = 0;
  for (; y; y /= 2, x = Mod(x + x)) {
    if (y & 1) {
      ret = Mod(ret + x);
    }
  }
  return ret;
}
struct graph {
  int cnt, h[N];
  pair<int, int> edge[N * 2];
  void add_edge(int x, int y) {
    edge[cnt].first = y;
    edge[cnt].second = h[x];
    h[x] = cnt++;
  }
  void clear() {
    memset(h, -1, sizeof h);
    cnt = 0;
  }
};
inline int ls(int k) { return k << 1; }
inline int rs(int k) { return k << 1 | 1; }
inline int sign(double x) {
  if (abs(x) < eps) {
    return 0;
  } else if (x < 0) {
    return -1;
  } else {
    return 1;
  }
}
template <typename T>
struct BIT {
  int limit;
  T vals[N];
  void resize(int n) { limit = n; }
  void add(int x, T y) {
    for (; x <= limit; x += x & -x) {
      vals[x] += y;
    }
  }
  T sum(int x) {
    T ret = 0;
    for (; x; x -= x & -x) {
      ret = ret + vals[x];
    }
    return ret;
  }
};
inline void flush() { std::cout << std::endl; }
template <typename T>
inline void readin(T *elem, int size) {
  for (int i = 1; i <= size; ++i) {
    std::cin >> elem[i];
  }
}
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
using std::ios;
using std::map;
using std::queue;
using std::set;
using std::vector;
int n, q, fa[N], dfc, dfn[N], low[N], rdfn[N * 2];
vector<int> son[N];
struct Node {
  int val, sum, mn, mx, fa, son[2], sz;
} kk[N * 2];
void dfs(int u) {
  rdfn[dfn[u] = ++dfc] = u;
  kk[dfc].mn = kk[dfc].mx = kk[dfc].sum = kk[dfc].val = 1;
  kk[dfc].sz = 1;
  for (auto &j : son[u]) {
    dfs(j);
  }
  rdfn[low[u] = ++dfc] = u;
  kk[dfc].mn = kk[dfc].mx = kk[dfc].sum = kk[dfc].val = -1;
  kk[dfc].sz = 1;
}
void maintain(int k) {
  kk[k].sum = kk[kk[k].son[0]].sum + kk[kk[k].son[1]].sum + kk[k].val;
  kk[k].mn = min(min(kk[kk[k].son[0]].mn, kk[kk[k].son[0]].sum + kk[k].val),
                 kk[kk[k].son[0]].sum + kk[k].val + kk[kk[k].son[1]].mn);
  kk[k].mx = max(max(kk[kk[k].son[0]].mx, kk[kk[k].son[0]].sum + kk[k].val),
                 kk[kk[k].son[0]].sum + kk[k].val + kk[kk[k].son[1]].mx);
  kk[k].sz = kk[kk[k].son[0]].sz + kk[kk[k].son[1]].sz + 1;
}
int merge(int x, int y) {
  if (!x || !y) {
    return x + y;
  }
  if (rand() % (kk[x].sz + kk[y].sz) < kk[x].sz) {
    kk[kk[x].son[1] = merge(kk[x].son[1], y)].fa = x;
    maintain(x);
    return x;
  } else {
    kk[kk[y].son[0] = merge(x, kk[y].son[0])].fa = y;
    maintain(y);
    return y;
  }
}
pair<int, int> split(int x, int sz) {
  if (!x) {
    return make_pair(0, 0);
  }
  pair<int, int> t;
  if (sz <= kk[kk[x].son[0]].sz) {
    t = split(kk[x].son[0], sz);
    kk[kk[x].son[0] = t.second].fa = x;
    maintain(t.second = x);
  } else {
    t = split(kk[x].son[1], sz - kk[kk[x].son[0]].sz - 1);
    kk[kk[x].son[1] = t.first].fa = x;
    maintain(t.first = x);
  }
  return t;
}
int get_sz(int k) {
  if (!k) {
    return 0;
  }
  int ret = kk[kk[k].son[0]].sz + 1;
  for (; kk[k].fa; k = kk[k].fa) {
    if (k == kk[kk[k].fa].son[1]) {
      ret += kk[kk[kk[k].fa].son[0]].sz + 1;
    }
  }
  return ret;
}
int build(int l, int r) {
  if (l > r) {
    return 0;
  }
  if (l == r) {
    return l;
  }
  int mid = (l + r) / 2;
  return merge(build(l, mid), build(mid + 1, r));
}
int find_last(int rt, int d) {
  while (rt) {
    if (kk[rt].son[1] &&
        kk[kk[rt].son[1]].mn <= d - kk[kk[rt].son[0]].sum - kk[rt].val &&
        d - kk[kk[rt].son[0]].sum - kk[rt].val <= kk[kk[rt].son[1]].mx) {
      d -= kk[kk[rt].son[0]].sum + kk[rt].val;
      rt = kk[rt].son[1];
    } else if (kk[rt].val + kk[kk[rt].son[0]].sum == d) {
      return rt;
    } else {
      rt = kk[rt].son[0];
    }
  }
}
int main() {
  srand(19260817);
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout << std::fixed << std::setprecision(10);
  kk[0].mn = INF;
  kk[0].mx = -INF;
  cin >> n >> q;
  for (int i = 1, x, y; i <= n; ++i) {
    cin >> x;
    for (int j = 1; j <= x; ++j) {
      cin >> y;
      fa[y] = i;
      son[i].push_back(y);
    }
  }
  dfs(1);
  int rt = build(1, 2 * n);
  for (int i = 1, op, x, y; i <= q; ++i) {
    cin >> op;
    switch (op) {
      case 1: {
        cin >> x >> y;
        int sz1 = get_sz(dfn[x]), sz2 = get_sz(dfn[y]);
        if (sz1 > sz2) {
          std::swap(sz1, sz2);
          std::swap(x, y);
        }
        pair<int, int> t = split(rt, sz1 - 1),
                       tt = split(t.second, sz2 - sz1 + 1);
        cout << (1 + kk[tt.first].sum - kk[tt.first].mn * 2) << '\n';
        kk[rt = merge(t.first, merge(tt.first, tt.second))].fa = 0;
      } break;
      case 2: {
        cin >> x >> y;
        int sz = get_sz(dfn[x]), sz1, sz2, sz3;
        pair<int, int> t = split(rt, sz);
        int tmp = find_last(t.first, kk[t.first].sum - y);
        fa[x] = tmp == dfn[rdfn[tmp]] ? rdfn[tmp] : fa[rdfn[tmp]];
        kk[rt = merge(t.first, t.second)].fa = 0;
        sz1 = get_sz(dfn[x]), sz2 = get_sz(low[x]), sz3 = get_sz(low[fa[x]]);
        t = split(rt, sz1 - 1);
        pair<int, int> tt = split(t.second, sz2 - sz1 + 1);
        pair<int, int> ttt = split(tt.second, sz3 - sz2 - 1);
        kk[rt = merge(t.first, merge(merge(ttt.first, tt.first), ttt.second))]
            .fa = 0;
      } break;
      case 3: {
        cin >> x;
        int tmp = find_last(rt, x + 1);
        cout << (tmp == dfn[rdfn[tmp]] ? rdfn[tmp] : fa[rdfn[tmp]]) << '\n';
      } break;
    }
  }
  cerr << "The time of this EXE is " << (((double)clock()) / CLOCKS_PER_SEC)
       << "s\n";
  return 0;
}
