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;
int read() {
  char k = getchar();
  int x = 0;
  while (k < '0' || k > '9') k = getchar();
  while (k >= '0' && k <= '9') x = x * 10 + k - '0', k = getchar();
  return x;
}
const int MX = 4e5 + 2333;
struct edge {
  int u, v, w;
  bool operator<(const edge &B) const { return w < B.w; }
} E[MX];
struct opt {
  int type, v;
} OP[MX * 2];
int a[MX], n, m, q, ncnt, tra[MX];
int fa[MX];
void init() {
  for (int i = 1; i < MX; ++i) fa[i] = i;
}
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
int par[20][MX], lim[MX], ch[MX][2];
int dfn[MX], L[MX], R[MX], dfscnt, refer[MX];
struct node {
  int l, r, mx, mxfr;
  node *lch, *rch;
  node operator+(node b) const {
    node c;
    c.mx = max(mx, b.mx);
    if (c.mx == mx)
      c.mxfr = mxfr;
    else
      c.mxfr = b.mxfr;
    return c;
  }
} * root;
void pushup(node *x) {
  x->mx = max(x->lch->mx, x->rch->mx);
  if (x->mx == x->lch->mx)
    x->mxfr = x->lch->mxfr;
  else
    x->mxfr = x->rch->mxfr;
}
node *build(int l, int r, int *_) {
  node *x = new node;
  x->l = l, x->r = r, x->mx = INT_MIN;
  if (l == r) {
    x->mx = _[l], x->mxfr = l;
    x->lch = x->rch = nullptr;
  } else {
    int mid = (l + r) >> 1;
    x->lch = build(l, mid, _);
    x->rch = build(mid + 1, r, _);
    pushup(x);
  }
  return x;
}
void initsegment(int x) {
  if (!ch[x][0]) {
    L[x] = R[x] = dfn[x] = ++dfscnt;
    refer[dfscnt] = x;
    return;
  }
  initsegment(ch[x][0]);
  initsegment(ch[x][1]);
  L[x] = L[ch[x][0]];
  R[x] = R[ch[x][1]];
}
void buildKruskal() {
  init();
  sort(E + 1, E + 1 + m);
  ncnt = n;
  for (int i = 1; i <= m; ++i) {
    int u = E[i].u, v = E[i].v;
    if (find(u) == find(v)) continue;
    par[0][find(u)] = par[0][find(v)] = ++ncnt;
    ch[ncnt][0] = find(u), ch[ncnt][1] = find(v);
    fa[find(u)] = fa[find(v)] = ncnt;
    lim[ncnt] = E[i].w;
  }
  int last = 1;
  for (int i = 1; i <= n; ++i) {
    if (find(last) != find(i)) {
      par[0][find(last)] = par[0][find(i)] = ++ncnt;
      ch[ncnt][0] = find(last), ch[ncnt][1] = find(i);
      fa[find(last)] = fa[find(i)] = ncnt;
      lim[ncnt] = INT_MAX;
      last = ncnt;
    }
  }
  for (int i = 1; i <= 18; ++i)
    for (int x = 1; x <= ncnt; ++x) par[i][x] = par[i - 1][par[i - 1][x]];
  initsegment(ncnt);
  for (int i = 1; i <= n; ++i) {
    tra[dfn[i]] = a[i];
  }
  root = build(1, n, tra);
}
int jump(int x, int limit) {
  for (int i = 18; ~i; --i)
    if (par[i][x] && lim[par[i][x]] <= limit) x = par[i][x];
  return x;
}
node query(node *x, int l, int r) {
  if (l <= x->l && x->r <= r) return *x;
  if (l <= x->lch->r && r > x->lch->r)
    return query(x->lch, l, r) + query(x->rch, l, r);
  if (l <= x->lch->r) return query(x->lch, l, r);
  return query(x->rch, l, r);
}
void change(node *x, int p, int v) {
  if (x->l == x->r) return x->mx = v, void();
  if (p <= x->lch->r)
    change(x->lch, p, v);
  else
    change(x->rch, p, v);
  return pushup(x);
}
int Query(int x, int limit) {
  x = jump(x, limit);
  node tmp = query(root, L[x], R[x]);
  change(root, tmp.mxfr, 0);
  return tmp.mx;
}
int main() {
  n = read(), m = read(), q = read();
  for (int i = 1; i <= n; ++i) {
    a[i] = read();
  }
  for (int i = 1, u, v; i <= m; ++i) {
    u = read(), v = read();
    E[i] = (edge){u, v, 0};
  }
  int eval = INT_MAX - 1;
  for (int i = 1, op, v; i <= q; ++i) {
    op = read(), v = read();
    OP[i] = (opt){op, v};
    if (op == 2) {
      E[v].w = eval--;
    }
  }
  buildKruskal();
  eval = INT_MAX - 1;
  for (int i = 1; i <= q; ++i) {
    if (OP[i].type == 1) {
      printf("%d\n", Query(OP[i].v, eval));
    } else {
      --eval;
    }
  }
  return 0;
}
