9 5 14
7 1 4 8 5 2 6 9 3
2 8
1 6
5 7
1 3
3 9
1 5
1 8
1 5
1 4
1 8
1 3
1 5
1 5
1 7
1 7
2 3
1 2
1 1
1 2
 6 5 8
1 2 6 3 4 5
2 4
1 3
1 6
3 5
2 5
1 1
1 4
1 1
2 1
2 5
2 2
2 3
1 4
 2 1 3
1 2
1 2
1 1
1 1
1 1

6
9
5
8
1
7
0
0
0
0
0
4
0
 6
5
4
3
 2
1
0

#include <bits/stdc++.h>
using namespace std;
namespace atcoder {
struct dsu {
 public:
  dsu() : _n(0) {}
  dsu(int n) : _n(n), parent_or_size(n, -1) {}
  int merge(int a, int b) {
    assert(0 <= a && a < _n);
    assert(0 <= b && b < _n);
    int x = leader(a), y = leader(b);
    if (x == y) return x;
    parent_or_size[x] += parent_or_size[y];
    parent_or_size[y] = x;
    return x;
  }
  bool same(int a, int b) {
    assert(0 <= a && a < _n);
    assert(0 <= b && b < _n);
    return leader(a) == leader(b);
  }
  int leader(int a) {
    assert(0 <= a && a < _n);
    if (parent_or_size[a] < 0) return a;
    return parent_or_size[a] = leader(parent_or_size[a]);
  }
  int size(int a) {
    assert(0 <= a && a < _n);
    return -parent_or_size[leader(a)];
  }
  std::vector<std::vector<int>> groups() {
    std::vector<int> leader_buf(_n), group_size(_n);
    for (int i = 0; i < _n; i++) {
      leader_buf[i] = leader(i);
      group_size[leader_buf[i]]++;
    }
    std::vector<std::vector<int>> result(_n);
    for (int i = 0; i < _n; i++) {
      result[i].reserve(group_size[i]);
    }
    for (int i = 0; i < _n; i++) {
      result[leader_buf[i]].push_back(i);
    }
    result.erase(
        std::remove_if(result.begin(), result.end(),
                       [&](const std::vector<int>& v) { return v.empty(); }),
        result.end());
    return result;
  }

 private:
  int _n;
  std::vector<int> parent_or_size;
};
}  // namespace atcoder
class SegTree {
 public:
  SegTree(int _n) : n(_n) {
    x = vector<pair<int, int>>(_n * 4);
    y = vector<int>(_n * 4);
  }
  void Build(int t, int l, int r) {
    if (l == r) {
      x[t] = {y[l], t};
      return;
    }
    int mid = (l + r) >> 1;
    Build(t + t, l, mid);
    Build(t + t + 1, mid + 1, r);
    x[t] = max(x[t + t], x[t + t + 1]);
  }
  pair<int, int> Query(int t, int l, int r, int p, int q) {
    if (p <= l && r <= q) return x[t];
    int mid = (l + r) >> 1;
    pair<int, int> res{};
    if (p <= mid) res = max(res, Query(t + t, l, mid, p, q));
    if (mid + 1 <= q) res = max(res, Query(t + t + 1, mid + 1, r, p, q));
    return res;
  }
  int Query(int p, int q) {
    auto [ans, t] = Query(1, 1, n, p, q);
    x[t] = {0, t};
    while (t > 1) {
      t /= 2;
      x[t] = max(x[t + t], x[t + t + 1]);
    }
    return ans;
  }
  int n;
  vector<pair<int, int>> x;
  vector<int> y;
};
class EulerTree {
 public:
  EulerTree(int _n)
      : n(_n),
        tree(_n + _n - 1),
        x(vector<vector<int>>(n + 1)),
        s(vector<int>(n + 1)),
        px(vector<vector<int>>(n + 1)) {}
  void AddEdge(int a, int b) { x[a].push_back(b); }
  void BuildDfs(int a, int fa) {
    dfsx.push_back(a);
    px[a].push_back(dfsx.size());
    s[a] = 1;
    for (int b : x[a]) {
      if (b == fa) continue;
      BuildDfs(b, a);
      s[a] += s[b];
      dfsx.push_back(a);
      px[a].push_back(dfsx.size());
    }
  }
  void Add(int a, int d) { tree.y[px[a].front()] = d; }
  void Build(int t) { BuildDfs(t, -1); }
  void BuildTree() { tree.Build(1, 1, n + n - 1); }
  int Query(int a) { return tree.Query(px[a].front(), px[a].back()); }
  int n;
  SegTree tree;
  vector<vector<int>> x;
  vector<int> s;
  vector<int> dfsx;
  vector<vector<int>> px;
};
struct Edge {
  int a, b, c;
};
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int n, m, k;
  cin >> n >> m >> k;
  vector<int> x(n);
  for (int i = 0; i < n; ++i) cin >> x[i];
  vector<Edge> y(m);
  for (int i = 0; i < m; ++i) cin >> y[i].a >> y[i].b;
  vector<Edge> q(k);
  int cnt = 0;
  for (int i = 0; i < k; ++i) {
    cin >> q[i].a >> q[i].b;
    if (q[i].a == 2) {
      y[q[i].b - 1].c = ++cnt;
    }
  }
  const int deletecnt = cnt;
  for (int i = 0; i < m; ++i) {
    if (y[i].c == 0) y[i].c = ++cnt;
  }
  sort(y.begin(), y.end(),
       [](const Edge& a, const Edge& b) { return a.c < b.c; });
  atcoder::dsu dsu(n + n);
  EulerTree tree(n + n - 1);
  cnt = n;
  for (int i = m - 1; i >= deletecnt; --i) {
    if (dsu.same(y[i].a, y[i].b)) continue;
    ++cnt;
    tree.AddEdge(cnt, dsu.leader(y[i].a));
    tree.AddEdge(cnt, dsu.leader(y[i].b));
    dsu.merge(cnt, y[i].a);
    dsu.merge(cnt, y[i].b);
  }
  for (int i = k - 1; i >= 0; --i) {
    if (q[i].a == 1) {
      q[i].c = dsu.leader(q[i].b);
    } else {
      int a = y[q[i].b - 1].a, b = y[q[i].b - 1].b;
      if (dsu.same(a, b)) continue;
      ++cnt;
      tree.AddEdge(cnt, dsu.leader(a));
      tree.AddEdge(cnt, dsu.leader(b));
      dsu.merge(cnt, a);
      dsu.merge(cnt, b);
    }
  }
  for (int i = 1; i <= n; ++i) {
    if (dsu.same(1, i)) continue;
    ++cnt;
    tree.AddEdge(cnt, dsu.leader(1));
    tree.AddEdge(cnt, dsu.leader(i));
    dsu.merge(cnt, 1);
    dsu.merge(cnt, i);
  }
  tree.Build(cnt);
  for (int i = 0; i < n; ++i) tree.Add(i + 1, x[i]);
  tree.BuildTree();
  for (int i = 0; i < k; ++i) {
    if (q[i].a == 2) continue;
    cout << tree.Query(q[i].c) << '\n';
  }
  return 0;
}
