#include <bits/stdc++.h>
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math,O3")
#pragma GCC target("sse4,sse4.2,popcnt,abm,mmx,avx")
using namespace std;
const int N = 1e6 + 5;
struct DSU {
  int par[N], sz[N], cnt;
  struct operation {
    int u, p, b, szb;
    bool ismerge;
  };
  stack<operation> stk;
  void init(int n) {
    iota(par, par + n, 0);
    fill(sz, sz + n, 1);
    cnt = n;
    stk = stack<operation>();
  }
  int operator[](int x) {
    if (par[x] == x) return x;
    stk.push({x, par[x], -1, -1, 0});
    return par[x] = (*this)[par[x]];
  }
  bool operator()(int a, int b) {
    a = (*this)[a];
    b = (*this)[b];
    if (a == b) return 0;
    if (sz[a] > sz[b]) swap(a, b);
    stk.push({a, par[a], b, sz[b], 1});
    par[a] = b;
    sz[b] += sz[a];
    cnt--;
    return true;
  }
  void rollback() {
    auto &op = stk.top();
    cnt += op.ismerge;
    par[op.u] = op.p;
    if (~op.b) {
      sz[op.b] = op.szb;
    }
    stk.pop();
  }
} dsu;
const int sz = (1 << 22);
vector<pair<int, int>> seg[sz];
int q;
void add(int qs, int qe, pair<int, int> edg, int id = 0, int ns = 0,
         int ne = q - 1) {
  if (qe < ns || qs > ne) return;
  if (ns >= qs && ne <= qe) {
    seg[id].push_back(edg);
    return;
  }
  int mid = ns + (ne - ns) / 2;
  int lf = 2 * id + 1;
  int rt = lf + 1;
  add(qs, qe, edg, lf, ns, mid);
  add(qs, qe, edg, rt, mid + 1, ne);
}
int ans[N];
int pos[N];
void dfs(int id = 0, int ns = 0, int ne = q - 1) {
  int stsz = dsu.stk.size();
  for (auto &p : seg[id]) {
    dsu(p.first, p.second);
  }
  if (ns == ne) {
    int x = pos[ns];
    x = dsu[x];
    ans[ns] = dsu.sz[x];
  } else {
    int mid = ns + (ne - ns) / 2;
    int lf = 2 * id + 1;
    int rt = lf + 1;
    dfs(lf, ns, mid);
    dfs(rt, mid + 1, ne);
  }
  while (dsu.stk.size() > stsz) dsu.rollback();
}
vector<pair<int, int>> eds[N];
vector<pair<int, pair<int, int>>> qss;
int main() {
  map<pair<int, int>, int> time;
  int n, k;
  scanf("%d %d %d", &n, &q, &k);
  int curd = 0;
  for (int i = 0; i < q; i++) {
    int t;
    scanf("%d", &t);
    if (t == 1) {
      int x, y;
      scanf("%d %d", &x, &y);
      x--;
      y--;
      qss.push_back({1, {x, y}});
      eds[curd].push_back({x, y});
    } else if (t == 2) {
      int x;
      scanf("%d", &x);
      x--;
      qss.push_back({0, {x, -1}});
    } else {
      curd++;
      if (curd - k < 0) continue;
      for (auto i : eds[curd - k]) qss.push_back({-1, i});
    }
  }
  vector<int> qr;
  dsu.init(n);
  q = qss.size();
  map<pair<int, int>, int> co;
  for (int i = 0; i < qss.size(); ++i) {
    if (qss[i].first == 0) {
      qr.push_back(i);
      pos[i] = qss[i].second.first;
    } else {
      int a = qss[i].second.first, b = qss[i].second.second;
      if (a > b) swap(a, b);
      co[{a, b}] += qss[i].first;
      if (co[{a, b}] == 1 && qss[i].first == 1) {
        time[{a, b}] = i;
      } else if (co[{a, b}] == 0 && qss[i].first == -1) {
        auto it = time.find({a, b});
        add(it->second, i - 1, {a, b});
        time.erase(it);
      }
    }
  }
  for (auto &p : time) {
    add(p.second, qss.size() - 1, p.first);
  }
  if (q > 0) dfs();
  for (auto x : qr) printf("%d\n", ans[x]);
}
