#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 10;
inline char nc() {
  static char buf[100000], *p1 = buf, *p2 = buf;
  if (p1 == p2) {
    p2 = (p1 = buf) + fread(buf, 1, 100000, stdin);
    if (p1 == p2) return EOF;
  }
  return *p1++;
}
inline void read(long long &x) {
  char c = nc(), b = 1;
  for (; !(c >= '0' && c <= '9'); c = nc())
    if (c == '-') b = -1;
  for (x = 0; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = nc())
    ;
  x *= b;
}
inline void read(int &x) {
  char c = nc(), b = 1;
  for (; !(c >= '0' && c <= '9'); c = nc())
    if (c == '-') b = -1;
  for (x = 0; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = nc())
    ;
  x *= b;
}
struct QUE {
  int op, day;
  int x, y;
  int ans;
} que[MAXN];
namespace DSU {
int f[MAXN], sz[MAXN], top;
struct node {
  int l, r;
  vector<pair<int, int> > val;
} T[MAXN * 2];
struct STK {
  int x, y;
} stk[MAXN * 2];
void init(int n) {
  for (int i = 1; i <= n; i++) {
    f[i] = i;
    sz[i] = 1;
  }
  top = 0;
}
int find(int x) { return f[x] == x ? x : find(f[x]); }
void merge(int x, int y) {
  int fx = find(x), fy = find(y);
  if (fx == fy) return;
  if (sz[fx] > sz[fy]) swap(fx, fy);
  sz[fy] += sz[fx];
  stk[++top] = {fx, fy};
  f[fx] = fy;
}
void build(int rt, int l, int r) {
  T[rt] = {l, r};
  if (l == r) {
    T[rt].val.clear();
    return;
  }
  build(rt << 1, l, ((T[rt].l + T[rt].r) >> 1));
  build(rt << 1 | 1, ((T[rt].l + T[rt].r) >> 1) + 1, r);
}
void update(int rt, int l, int r, int x, int y) {
  if (l <= T[rt].l && T[rt].r <= r) {
    T[rt].val.push_back(make_pair(x, y));
    return;
  }
  if (l <= ((T[rt].l + T[rt].r) >> 1)) update(rt << 1, l, r, x, y);
  if (r > ((T[rt].l + T[rt].r) >> 1)) update(rt << 1 | 1, l, r, x, y);
}
void solve(int rt) {
  int lasttop = top;
  for (auto tmp : T[rt].val) {
    merge(tmp.first, tmp.second);
  }
  if (T[rt].l == T[rt].r) {
    if (que[T[rt].l].op == 2) {
      que[T[rt].l].ans = sz[find(que[T[rt].l].x)];
    }
    while (top > lasttop) {
      sz[stk[top].y] -= sz[stk[top].x];
      f[stk[top].x] = stk[top].x;
      top--;
    }
    return;
  }
  solve(rt << 1);
  solve(rt << 1 | 1);
  while (top > lasttop) {
    sz[stk[top].y] -= sz[stk[top].x];
    f[stk[top].x] = stk[top].x;
    top--;
  }
}
}  // namespace DSU
int main() {
  int n, m, k;
  read(n), read(m), read(k);
  DSU::init(n);
  DSU::build(1, 1, m);
  int now = 1;
  vector<int> endtime(m + 1);
  for (int i = 1; i <= m; i++) {
    que[i].day = now;
    read(que[i].op);
    if (que[i].op == 1) {
      read(que[i].x), read(que[i].y);
    } else if (que[i].op == 2) {
      read(que[i].x);
    } else {
      endtime[now] = i;
      now++;
    }
  }
  endtime[now] = m;
  for (int i = 1; i <= m; i++) {
    if (que[i].op == 1) {
      int right = min(now, que[i].day + k - 1);
      DSU::update(1, i, endtime[right], que[i].x, que[i].y);
    }
  }
  DSU::solve(1);
  for (int i = 1; i <= m; i++) {
    if (que[i].op == 2) {
      printf("%d\n", que[i].ans);
    }
  }
  return 0;
}
