#include <bits/stdc++.h>
using namespace std;
const int inf = 1e9;
const double pi = acos(-1);
const int SLMT = 1e5 + 5;
const int ALMT = 1e6 + 5;
template <class T>
inline void sd(T &num) {
  num = 0;
  int sign = 0;
  char ch;
  while (isspace(ch = getchar()))
    ;
  if (isdigit(ch))
    num = ch - '0';
  else
    sign = ch == '+' ? 0 : 1;
  while (isdigit(ch = getchar())) num = (num << 3) + (num << 1) + ch - '0';
  num = sign ? -num : num;
}
template <class T>
inline void pd(T num, char ch = ' ') {
  if (num < 0) {
    putchar('-');
    num = -num;
  }
  char digits[21] = {};
  int pos = 1;
  do {
    digits[pos++] = '0' + num % 10;
  } while (num /= 10);
  while (--pos) putchar(digits[pos]);
  putchar(ch);
}
template <class T>
inline void iArr(T &arr, int size) {
  for (auto i = 0; i != size; ++i) sd(arr[i]);
}
template <class T>
inline int mArr(T &arr, int size) {
  int val;
  int mval = INT_MIN;
  for (auto i = 0; i != size; ++i) sd(val), ++arr[val], mval = max(mval, val);
  return mval;
}
template <class T>
inline void oArr(T &arr, int size) {
  for (auto i = 0; i != size; ++i) pd(arr[i]);
  putchar('\n');
}
template <class T>
inline void iMat(T &mat, int n, int m) {
  for (auto i = 0; i != n; ++i)
    for (auto j = 0; j != m; ++j) sd(mat[i][j]);
}
template <class T>
inline void oMat(T &mat, int n, int m) {
  for (auto i = 0; i != n; ++i) {
    for (auto j = 0; j != m; ++j) pd(mat[i][j]);
    putchar('\n');
  }
}
inline void oMat(char **mat, int n) {
  for (auto i = 0; i != n; ++i) puts(mat[i]);
}
inline void iMat(char **mat, int n) {
  for (auto i = 0; i != n; ++i) scanf("%s", mat[i]);
}
template <class T>
inline void MAT(T **&mat, int r, int c, T val = 0) {
  mat = new T *[r];
  if (!val) {
    for (auto i = 0; i != r; ++i) mat[i] = new T[c + 1]();
    return;
  }
  for (auto i = 0; i != r; ++i) {
    mat[i] = new T[c + 1];
    for (auto j = 0; j != c + 1; ++j) mat[i][j] = val;
  }
}
template <class T>
inline void ARR(T *&arr, int n, int val = 0) {
  if (!val) {
    arr = new T[n]();
    return;
  }
  arr = new T[n];
  fill(arr, arr + n, val);
}
const int MAXN = 1e6 + 5;
int par[MAXN], rnk[MAXN];
inline void init(int n) { iota(par + 1, par + n + 1, 1); }
inline int getRoot(int x) {
  return par[x] = (par[x] == x ? x : getRoot(par[x]));
}
inline void Union(int p, int q) { par[getRoot(p)] = getRoot(q); }
void newUnion(int p, int q) {
  if ((p = getRoot(p)) == (q = getRoot(q))) return;
  par[q] = p;
  rnk[p] = max(max(rnk[p], rnk[q]), rnk[p] / 2 + 1 + rnk[q] / 2 + 1);
}
struct edge {
  int to, next;
} edges[MAXN];
int pos = 0;
int st[MAXN];
void addEdge(int u, int v) {
  edges[++pos] = (edge){v, st[u]};
  st[u] = pos;
}
int seen[MAXN];
int n;
int longestPath[MAXN];
int longestDepth[MAXN];
stack<int> s;
void dfs(int j) {
  seen[j] = 1;
  s.push(j);
  int lPath = 0;
  int fLong = 0, sLong = 0, depth = 1;
  for (int i = st[j]; i; i = edges[i].next) {
    int x = edges[i].to;
    if (!seen[x]) {
      dfs(x);
      if (longestDepth[x] > fLong)
        sLong = fLong, fLong = longestDepth[x];
      else if (longestDepth[x] > sLong)
        sLong = longestDepth[x];
      lPath = max(lPath, longestPath[x]);
    }
  }
  longestPath[j] = max(1 + fLong + sLong, lPath);
  longestDepth[j] = fLong + 1;
}
void pushIntoDsu(int r) {
  while (!s.empty()) {
    Union(r, s.top());
    s.pop();
  }
  rnk[getRoot(r)] = longestPath[r];
}
void loadDiameters() {
  init(n + 1);
  for (auto i = 1; i != n + 1; ++i)
    if (!seen[i]) {
      dfs(i);
      pushIntoDsu(i);
    }
}
int main(void) {
  sd(n);
  int e;
  sd(e);
  int q;
  sd(q);
  for (auto i = 0; i != e; ++i) {
    int x, y;
    sd(x), sd(y);
    addEdge(x, y);
    addEdge(y, x);
  }
  loadDiameters();
  for (auto i = 0; i != q; ++i) {
    int a, b, c;
    sd(a), sd(b);
    if (a == 2) {
      sd(c);
      newUnion(b, c);
    } else
      pd(rnk[getRoot(b)] - 1, '\n');
  }
  return 0;
}
