#include <bits/stdc++.h>
using namespace std;
template <typename T>
void read(T &x) {
  x = 0;
  char ch = getchar();
  long long f = 1;
  while (!isdigit(ch)) {
    if (ch == '-') f *= -1;
    ch = getchar();
  }
  while (isdigit(ch)) {
    x = x * 10 + ch - 48;
    ch = getchar();
  }
  x *= f;
}
template <typename T, typename... Args>
void read(T &first, Args &...args) {
  read(first);
  read(args...);
}
template <typename T>
void write(T arg) {
  T x = arg;
  if (x < 0) {
    putchar('-');
    x = -x;
  }
  if (x > 9) {
    write(x / 10);
  }
  putchar(x % 10 + '0');
}
template <typename T, typename... Ts>
void write(T arg, Ts... args) {
  write(arg);
  if (sizeof...(args) != 0) {
    putchar(' ');
    write(args...);
  }
}
using namespace std;
long long gcd(long long a, long long b) { return b == 0 ? a : gcd(b, a % b); }
long long lcm(long long a, long long b) { return a / gcd(a, b) * b; }
const int N = 6e5 + 5;
int n, Q, k, pp;
vector<int> v[N << 2];
int ans[N];
struct node {
  int op, x, y;
} in[N];
vector<int> three;
struct Undo_Dsu {
  stack<pair<int, int> > st;
  int fa[N], siz[N];
  void init() {
    while (!st.empty()) st.pop();
    for (int i = 1; i <= N - 5; i++) fa[i] = i, siz[i] = 1;
  }
  int findroot(int x) { return x == fa[x] ? x : findroot(fa[x]); }
  bool merge(int u, int v) {
    int fax = findroot(u), fay = findroot(v);
    if (fax == fay) return 0;
    if (siz[fax] > siz[fay]) swap(fax, fay), swap(u, v);
    fa[fax] = fay, siz[fay] += siz[fax];
    st.push({fax, fay});
    return 1;
  }
  void undo() {
    pair<int, int> no = st.top();
    fa[no.first] = no.first;
    siz[no.second] -= siz[no.first];
    st.pop();
  }
} dsu;
void insert(int i, int L, int R, int l, int r, int val) {
  if (L > r || R < l) return;
  if (l <= L && R <= r) {
    v[i].push_back(val);
    return;
  }
  int mid = (L + R) >> 1;
  insert(i << 1, L, mid, l, r, val);
  insert(i << 1 | 1, mid + 1, R, l, r, val);
}
void dfs(int i, int L, int R) {
  int t = (int)dsu.st.size();
  for (auto it : v[i]) {
    if (in[it].op == 1) {
      int u = in[it].x, vv = in[it].y;
      dsu.merge(u, vv);
    }
  }
  for (auto it : v[i]) {
    if (in[it].op == 2) {
      ans[it] = dsu.siz[dsu.findroot(in[it].x)];
    }
  }
  if (L == R) {
    while ((int)dsu.st.size() > t) dsu.undo();
    return;
  }
  int mid = (L + R) >> 1;
  dfs(i << 1, L, mid);
  dfs(i << 1 | 1, mid + 1, R);
  while ((int)dsu.st.size() > t) dsu.undo();
  return;
}
int main() {
  memset(ans, -1, sizeof(ans));
  three.push_back(0);
  read(n, Q, k);
  for (int i = 1; i <= Q; i++) {
    read(in[i].op);
    if (in[i].op == 1) read(in[i].x, in[i].y);
    if (in[i].op == 2) {
      read(in[i].x);
      insert(1, 1, Q, i, i, i);
    }
    if (in[i].op == 3) three.push_back(i), pp++;
  }
  three.push_back(Q + 1);
  int sz = (int)three.size();
  for (int i = 1; i < three.size(); i++) {
    for (int l = three[i - 1]; l <= three[i]; l++) {
      if (in[l].op == 1) {
        int r = Q;
        if (i + k - 1 < sz) r = three[i + k - 1];
        insert(1, 1, Q, l, r, l);
      }
    }
  }
  dsu.init();
  dfs(1, 1, Q);
  for (int i = 1; i <= Q; i++)
    if (in[i].op == 2) write(ans[i]), putchar('\n');
}
