You are given an undirected graph consisting of $$$n$$$ vertices and $$$m$$$ edges. Initially there is a single integer written on every vertex: the vertex $$$i$$$ has $$$p_i$$$ written on it. All $$$p_i$$$ are distinct integers from $$$1$$$ to $$$n$$$.You have to process $$$q$$$ queries of two types:  $$$1$$$ $$$v$$$ — among all vertices reachable from the vertex $$$v$$$ using the edges of the graph (including the vertex $$$v$$$ itself), find a vertex $$$u$$$ with the largest number $$$p_u$$$ written on it, print $$$p_u$$$ and replace $$$p_u$$$ with $$$0$$$;  $$$2$$$ $$$i$$$ — delete the $$$i$$$-th edge from the graph.  Note that, in a query of the first type, it is possible that all vertices reachable from $$$v$$$ have $$$0$$$ written on them. In this case, $$$u$$$ is not explicitly defined, but since the selection of $$$u$$$ does not affect anything, you can choose any vertex reachable from $$$v$$$ and print its value (which is $$$0$$$).

The first line contains three integers $$$n$$$, $$$m$$$ and $$$q$$$ ($$$1 \le n \le 2 \cdot 10^5$$$; $$$1 \le m \le 3 \cdot 10^5$$$; $$$1 \le q \le 5 \cdot 10^5$$$). The second line contains $$$n$$$ distinct integers $$$p_1$$$, $$$p_2$$$, ..., $$$p_n$$$, where $$$p_i$$$ is the number initially written on vertex $$$i$$$ ($$$1 \le p_i \le n$$$). Then $$$m$$$ lines follow, the $$$i$$$-th of them contains two integers $$$a_i$$$ and $$$b_i$$$ ($$$1 \le a_i, b_i \le n$$$, $$$a_i \ne b_i$$$) and means that the $$$i$$$-th edge connects vertices $$$a_i$$$ and $$$b_i$$$. It is guaranteed that the graph does not contain multi-edges. Then $$$q$$$ lines follow, which describe the queries. Each line is given by one of the following formats:   $$$1$$$ $$$v$$$ — denotes a query of the first type with a vertex $$$v$$$ ($$$1 \le v \le n$$$).  $$$2$$$ $$$i$$$ — denotes a query of the second type with an edge $$$i$$$ ($$$1 \le i \le m$$$). For each query of the second type, it is guaranteed that the corresponding edge is not deleted from the graph yet.

For every query of the first type, print the value of $$$p_u$$$ written on the chosen vertex $$$u$$$.

#include<cstdio>
#include<algorithm>
struct read{
	static const int bufsize=1<<24;
	char buf[bufsize],*p1,*p2,c,f;
	read():buf(),p1(buf),p2(buf){}
	char gc(){
		return p1==p2&&(p2=buf+fread(p1=buf,1,bufsize,stdin),p1==p2)?EOF:*p1++;
	}
	read& operator >> (int& x){
		for(x=0,c=gc(),f=0;~c&&(c<'0'||c>'9');c=gc())if(c=='-')f=1;
		if(f)for(;c<='9'&&c>='0';c=gc())x=x*10+'0'-c;
		else for(;c<='9'&&c>='0';c=gc())x=x*10-'0'+c;
		return *this;
	}
	read& operator >> (long long& x){
		for(x=0,c=gc(),f=0;~c&&(c<'0'||c>'9');c=gc())if(c=='-')f=1;
		if(f)for(;c<='9'&&c>='0';c=gc())x=x*10+'0'-c;
		else for(;c<='9'&&c>='0';c=gc())x=x*10-'0'+c;
		return *this;
	}
}in;
struct write{
	static const int bufsize=1<<23;
	char buf[bufsize],*p1,*p2,s[50];
	int tp;
	write():p1(buf),p2(buf+bufsize){}
	~write(){flush();}
	void flush(void){
		fwrite(buf,1,p1-buf,stdout),p1=buf;
	}
	void pc(const char& c){
		if(p1==p2)flush();
		*p1++=c;
	}
	write& operator <<(int x){
		if(x<0)x=-x,pc('-');
		do{s[tp++]=x%10+'0',x/=10;}while(x);
		while(tp)pc(s[--tp]);
		return *this;
	}
	write& operator <<(const char& x){
		pc(x);
		return *this;
	}
}out;
int n,m,q,a[200010];
struct edge{
	int u,v,t;
	bool operator <(edge const &x)const{
		return t<x.t;
	}
}p[300010];
struct ask{
	int op,u,l,r;
}t[500010];
int f[200010],cnt,hd[200010],ed[200010],pre[200010],nxt[200010];
int find(int x){
	while(x!=f[x])x=f[x]=f[f[x]];
	return x;
}
int dfn[200010],rk[200010];
struct node{
	int v,p;
}tr[800010];
void pushup(int const &x,int const &ls,int const &rs){
	if(tr[ls].v>tr[rs].v) tr[x]=tr[ls];
	else tr[x]=tr[rs];
}
void build(int const &x=1,int const &l=1,int const &r=n){
	if(l==r) return tr[x].v=a[rk[l]],tr[x].p=l,void();
	int mid=(l+r)>>1,ls=x<<1,rs=x<<1|1;
	build(ls,l,mid),build(rs,mid+1,r);
	pushup(x,ls,rs);
}
node query(int const &pl,int const &pr,int const &x=1,int const &l=1,int const &r=n){
	if(l==pl&&r==pr) return tr[x];
	int mid=(l+r)>>1,ls=x<<1,rs=x<<1|1;
	if(pr<=mid) return query(pl,pr,ls,l,mid);
	else if(pl>mid) return query(pl,pr,rs,mid+1,r);
	else{
		node ll=query(pl,mid,ls,l,mid),rl=query(mid+1,pr,rs,mid+1,r);
		return ll.v>rl.v?ll:rl;
	}
}
void update(int const &p,int const &x=1,int const &l=1,int const &r=n){
	if(l==r) return tr[x].v=0,void();
	int mid=(l+r)>>1,ls=x<<1,rs=x<<1|1;
	if(p<=mid) update(p,ls,l,mid);
	else update(p,rs,mid+1,r);
	pushup(x,ls,rs);
}
int main(){
    in>>n>>m>>q;
	for(int i=1;i<=n;i++)in>>a[i],f[i]=i,hd[i]=ed[i]=i;
	for(int i=1;i<=m;i++)in>>p[i].u>>p[i].v,p[i].t=q+1;
	for(int i=1;i<=q;i++)in>>t[i].op>>t[i].u;
	for(int i=1;i<=q;i++)if(t[i].op==2)p[t[i].u].t=i;
	std::sort(p+1,p+m+1);
	int tmp=q;
	for(int i=m;i;i--){
		for(;tmp>=p[i].t;--tmp){
			if(t[tmp].op==2) continue;
			int x=find(t[tmp].u);
			t[tmp].l=hd[x],t[tmp].r=ed[x];
		}
		int x=find(p[i].u),y=find(p[i].v);
		if(x==y) continue;
		nxt[ed[x]]=hd[y];
		pre[hd[y]]=ed[x];
		f[x]=y,hd[y]=hd[x];
	}
	for(;tmp;--tmp){
		if(t[tmp].op==2) continue;
		int x=find(t[tmp].u);
		t[tmp].l=hd[x],t[tmp].r=ed[x];
	}
	for(int i=1;i<=n;i++)
		if(!pre[i])
			for(int k=i;k;k=nxt[k])
				rk[dfn[k]=++cnt]=k;
	build();
	for(int i=1;i<=q;i++){
		if(t[i].op==2) continue;
		node w=query(dfn[t[i].l],dfn[t[i].r]);
		out<<w.v<<'\n';
		update(w.p);
	}
	return 0;
}

#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define f first
#define s second
using namespace std;
const int mxn=2e5+5;
const int mxm=3e5+5;
const int mxq=5e5+5;

const int inf=1e9;
int p[mxn];
int L[mxm],R[mxm];
bool usd[mxm];
int tp[mxq],id[mxq];

struct reachability_tree {
	int parent[mxn];
	int sz[mxn];
	int in[mxn],out[mxn],id[mxn];
	int pc[mxn];
	vector<int> g[mxn];
	vector<int> w[mxn];
	int T=0;

	void init(int n) {
		for(int i=1;i<=n;i++) {
			parent[i] = i;
			sz[i] = 1;
		}
	}

	int findrep(int u) {
		return parent[u] == u ? u : findrep(parent[u]);
	}

	void unite(int u,int v,int cst) {
		u=findrep(u);
		v=findrep(v);
		if(u == v) return;

		if(sz[u] > sz[v]) swap(u,v);

		parent[u] = v;
		sz[v] += sz[u];
		g[v].push_back(u);
		w[v].push_back(cst);
		pc[u] = cst;

	}
	void dfs(int u) {
		in[u] = ++T;
		id[T] = u;
		for(int v : g[u]) {
			dfs(v);
		}
		out[u] = T;
	}

	pii range(int u, int tm) {
		while(parent[u] != u && pc[u] >= tm) u = parent[u];

		int p = upper_bound(w[u].begin(),w[u].end(),tm,[](int a,int b) {
			return a > b;
		}) - w[u].begin();

		if(p == 0) {
			return {in[u], in[u]};
		}

		int v = g[u][p-1];
		return {in[u],out[v]};
	}

} rt ;

struct segtree {
	pii tree[4*mxn];

	void update(int node,int b,int e,int p,int v) {
		if(e<p || b>p) return;
		if(b == e) {
			tree[node] = {v,b};
			return;
		}

		int mid=b+e>>1;
		int left=node<<1;
		int right=left|1;

		update(left,b,mid,p,v);
		update(right,mid+1,e,p,v);
		tree[node]=max(tree[left],tree[right]);
	}

	pii query(int node,int b,int e,int l,int r) {
		if(b > r || e < l) return {0,0};

		if(b >=l && e <=r ) return tree[node];

		int mid=b+e>>1;
		int left=node<<1;
		int right=left|1;

		return max(query(left,b,mid,l,r) , query(right,mid+1,e,l,r));

	}
} st;

int main() {
	int n,m,q;
	cin>>n>>m>>q;

	for(int i=1;i<=n;i++) {
		scanf("%d",&p[i]);
	}

	for(int i=1;i<=m;i++) {
		scanf("%d%d",&L[i], &R[i]);
	}

	for(int i=1;i<=q;i++) {
		scanf("%d %d", &tp[i], &id[i]);

		if(tp[i]==2) usd[id[i]] = true;
	}
	rt.init(n);

	for(int i=1;i<=m;i++) {
		if(!usd[i]) rt.unite(L[i],R[i],inf);
	}

	for(int i=q;i>0;i--) {
		if(tp[i] == 2) rt.unite(L[id[i]],R[id[i]],i);
	}

	for(int i=1;i<=n;i++) {
	    if(rt.findrep(i) == i) {
	        rt.dfs(i);
	    }
	}

	for(int i=1;i<=n;i++) {
		st.update(1,1,n,rt.in[i],p[i]);
	}
	bool dn[mxn]={};

	for(int i=1;i<=q;i++) {
		if(tp[i] == 1) {
			pii rg= rt.range(id[i],i);
			pii x = st.query(1,1,n,rg.f,rg.s);

			if(x.f == 0) {
				printf("0\n");
			} else {
				printf("%d\n", x.f);
				if(dn[x.s]) continue;
				st.update(1,1,n,x.s,0);
			}
		}
	}

}

// Mivik 2020.9.29
#include <iostream>
#include <cstring>
#include <cstdio>

#define d isdigit(c)
#define g c=t.get();
#define L return
#define K break
#define A(c,a,b)if(c)a else b;
#define I(c,a)if(c)a;
#define Y goto E
struct MI{private:char bb[4096];FILE*f;char*bs,*be;char e;bool o,l;public:MI():f(stdin){}
#ifdef __linux__
#endif
inline char get(){if(o){o=0;L e;}
#ifdef MIVIK
char c=fgetc(f);I(c==-1,l=1)L c;
#else
I(bs==be,be=(bs=bb)+fread(bb,1,sizeof(bb),f))I(bs==be,{l=1;L-1;})L*bs++;
#endif
}inline void unget(char c){o=1;e=c;}template<typename T>inline T read(){T r;*this>r;L r;}template<typename T>inline MI&operator>(T&);};template<typename T>struct Q{const static bool U=T(-1)>=T(0);inline void operator()(MI&t,T&r)const{r=0;char c;bool y=0;A(U,for(;;){g I(c==-1,Y)I(d,K)},for(;;){g I(c==-1,Y)A(c=='-',{g I(d,{y=1;K;})},I(d,K))})for(;;){I(c==-1,Y)A(d,r=r*10+(c^48);,K)g}t.unget(c);E:;I(y,r=-r)}};template<>struct Q<char>{};template<typename T>inline MI&MI::operator>(T&t){Q<T>()(*this,t);L*this;}
#undef d
#undef g
#undef L
#undef K
#undef A
#undef I
#undef Y
template<typename T>std::ostream& operator<(std::ostream&out,const T&t){return out<<t;}
#define endl ('\n')
#define P(x) cout < #x" = " < (x) < endl
#define R (cin.read<int>())

using std::cout;

#include <climits>

using std::make_pair;
using std::pair;

#ifdef MIVIK
MI cin(popen("xsel -ob", "r"));
#else
MI cin;
#endif

const int nmax = 200001;
const int pmax = nmax * 2;
const int qmax = 500005;
const int tmax = 1048577;

template<typename T> inline bool getmax(T &a, const T &b) { return a < b && (a = b, true); }

int n, m, q;
int a[nmax];
int fro[qmax], tar[qmax];
bool del[qmax];
pair<bool, int> qs[qmax];
int tot;
int f[pmax], ls[pmax], rs[pmax], rin[pmax], ind[pmax], rig[pmax], val[pmax];

namespace seg {
#define ls (x << 1)
#define rs (ls | 1)
#define G const int mid = (l + r) >> 1
#define LL ls, l, mid
#define RR rs, mid + 1, r

int mx[tmax], ll, rr, vv, tx, tl, tr;
inline void pu(int x) { mx[x] = std::max(mx[ls], mx[rs]); }
void _build(int x, int l, int r) {
	if (l == r) return (void)(mx[x] = val[l]);
	G;
	_build(LL);
	_build(RR);
	pu(x);
}
inline void build() { _build(1, 1, tot); }
void _clear(int x, int l, int r) {
	if (l == r) return (void)(mx[x] = 0);
	G;
	(mx[ls] == mx[x]) ? _clear(LL) : _clear(RR);
	pu(x);
}
void _query(int x, int l, int r) {
	if (ll <= l && r <= rr) {
		if (getmax(vv, mx[x])) {
			tx = x;
			tl = l;
			tr = r;
		}
		return;
	}
	G;
	if (ll <= mid) _query(LL);
	if (mid < rr) _query(RR);
}
inline int query(int l, int r) {
	ll = l;
	rr = r;
	vv = 0;
	_query(1, 1, tot);
	if (vv) _clear(tx, tl, tr);
	return vv;
}

#undef ls
#undef rs
#undef G
#undef LL
#undef RR
} // namespace seg

int getf(int x) { return (x == f[x]) ? x : (f[x] = getf(f[x])); }
inline void merge(int x, int y) {
	x = getf(x);
	y = getf(y);
	if (x == y) return;
	const int t = ++tot;
	f[x] = f[y] = f[t] = t;
	ls[t] = x;
	rs[t] = y;
}
void dfs(int x) {
	static int tot;
	if (!x) return;
	ind[x] = ++tot;
	val[tot] = (x <= n) ? a[x] : INT_MIN;
	dfs(ls[x]);
	dfs(rs[x]);
	rig[x] = tot;
}
int main() {
	cin > n > m > q;
	for (int i = 1; i <= n; ++i) {
		cin > a[i];
		f[i] = i;
	}
	for (int i = 1; i <= m; ++i) cin > fro[i] > tar[i];
	for (int i = 1; i <= q; ++i) {
		const int op = R;
		qs[i] = make_pair(op == 2, R);
		if (op == 2) del[qs[i].second] = 1;
	}
	tot = n;
	for (int i = 1; i <= m; ++i)
		if (!del[i]) merge(fro[i], tar[i]);
	for (int i = q; i; --i) {
		auto &pa = qs[i];
		if (pa.first)
			merge(fro[pa.second], tar[pa.second]);
		else
			pa.second = getf(pa.second);
	}
	for (int i = 1; i <= tot; ++i)
		if (getf(i) == i) dfs(i);
	seg::build();
	for (int i = 1; i <= q; ++i) {
		const auto &pa = qs[i];
		if (pa.first) continue;
		cout < seg::query(ind[pa.second], rig[pa.second]) < endl;
	}
	return 0;
}

#include<bits/stdc++.h>

#define pb push_back
#define eb emplace_back
#define mp make_pair
#define fi first
#define se second
#define all(x) (x).begin(), (x).end()
#define debug(x) cerr << #x << " = " << x << endl;

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int MAXN = (int)5e5 + 5;
const int MAXM = (int)3e5 + 5;
const int MAXQ = (int)5e5 + 5;

pii e[MAXM], que[MAXQ], t[MAXN << 2];
vector<int> adj[MAXN];
int tin[MAXN], tout[MAXN], timer;
int par[MAXN], arr[MAXN];
bool del[MAXM];
int n, m, q;

int getPar(int x) {
  if (x == par[x]) {
    return x;
  }

  return par[x] = getPar(par[x]);
}

void uni(int a, int b) {
  a = getPar(a);
  b = getPar(b);

  if (a == b) {
    return;
  }

  ++n;
  par[n] = n;
  par[a] = n;
  par[b] = n;
  adj[n].pb(a);
  adj[n].pb(b);
}

void dfs(int v) {
  tin[v] = ++timer;

  for (int to : adj[v]) {
    dfs(to);
  }

  tout[v] = timer;
}

pii segMax(int v, int tl, int tr, int l, int r) {
  if (l > r || tl > r || tr < l) {
    return mp(0, 0);
  }

  if (l <= tl && tr <= r) {
    return t[v];
  }

  int mid = (tl + tr) >> 1;
  int c1 = (v << 1), c2 = (c1 | 1);

  return max(segMax(c1, tl, mid, l, r), segMax(c2, mid + 1, tr, l, r));
}

void updPos(int v, int tl, int tr, int p, pii x) {
  if (tl == tr) {
    t[v] = x;
    return;
  }

  int mid = (tl + tr) >> 1;
  int c1 = (v << 1), c2 = (c1 | 1);

  if (p <= mid) {
    updPos(c1, tl, mid, p, x);
  }
  else {
    updPos(c2, mid + 1, tr, p, x);
  }

  t[v] = max(t[c1], t[c2]);
}

void solve() {
  scanf("%d %d %d", &n, &m, &q);

  for (int i = 1; i <= n; ++i) {
    scanf("%d", &arr[i]);
  }

  for (int i = 1; i <= m; ++i) {
    int u, v;
    scanf("%d %d", &u, &v);
    e[i] = mp(u, v);
  }

  for (int i = 1; i <= q; ++i) {
    int a, b;
    scanf("%d %d", &a, &b);
    que[i] = mp(a, b);

    if (a == 2) {
      del[b] = 1;
    }
  }

  for (int i = 1; i <= n; ++i) {
    par[i] = i;
  }

  for (int i = 1; i <= m; ++i) {
    if (!del[i]) {
      uni(e[i].fi, e[i].se);
    }
  }

  for (int i = q; i > 0; --i) {
    int tp = que[i].fi;

    if (tp == 2) {
      int id = que[i].se;
      uni(e[id].fi, e[id].se);
    }
    else {
      que[i].se = getPar(que[i].se);
    }
  }

  for (int i = 1; i <= n; ++i) {
    if (getPar(i) == i) {
      dfs(i);
    }
  }

  for (int i = 1; i <= n; ++i) {
    updPos(1, 1, n, tin[i], mp(arr[i], tin[i]));
  }

  for (int i = 1; i <= q; ++i) {
    int tp = que[i].fi;

    if (tp == 1) {
      int v = que[i].se;
      pii tmp = segMax(1, 1, n, tin[v], tout[v]);

      if (tmp.fi == 0) {
        printf("0\n");
      }
      else {
        printf("%d\n", tmp.fi);
        updPos(1, 1, n, tmp.se, mp(0, 0));
      }
    }
  }
}

int main() {
  int tt = 1;

  while (tt--) {
    solve();
  }

  return 0;
}

#include <bits/stdc++.h>

int32_t main() {
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
#endif
    int32_t n, m, q;
    scanf("%d%d%d", &n, &m, &q);
    std::vector<int32_t> a(n);
    for (int32_t i = 0; i < n; i++)
        scanf("%d", &a[i]);
    std::vector<std::pair<int32_t, int32_t>> edges(m);
    for (int32_t i = 0; i < m; i++) {
        scanf("%d%d", &edges[i].first, &edges[i].second);
        --edges[i].first;
        --edges[i].second;
    }
    std::vector<bool> removed(m);
    std::vector<std::pair<int32_t, int32_t>> queries(q);
    for (int32_t i = 0; i < q; i++) {
        scanf("%d%d", &queries[i].first, &queries[i].second);
        --queries[i].second;
        if (queries[i].first == 2)
            removed[queries[i].second] = true;
    }
    std::vector<int32_t> parent(n, -1);
    auto find = [&](int32_t x) {
        while (0 <= parent[x]) x = parent[x];
        return x;
    };
    std::vector<std::vector<int32_t>> adj(n);
    auto merge = [&](int32_t u, int32_t v) {
        u = find(u), v = find(v);
        if (u == v) return;
        if (parent[u] < parent[v])
            std::swap(u, v);
        parent[v] += parent[u];
        adj[v].push_back(u);
        parent[u] = v;
    };
    for (int32_t i = 0; i < m; i++) {
        if (removed[i]) continue;
        merge(edges[i].first, edges[i].second);
    }
    std::vector<int32_t> children;
    for (int32_t i = q; i --> 0;) {
        if (queries[i].first == 1) {
            int32_t x = find(queries[i].second);
            queries[i].second = x;
            children.push_back(adj[x].empty() ? -1 : adj[x].back());
        } else {
            auto edge = edges[queries[i].second];
            merge(edge.first, edge.second);
        }
    }
    std::reverse(children.begin(), children.end());
    std::vector<std::pair<int32_t, int32_t>> tree;
    tree.reserve(n + n);
    tree.resize(n);
    int32_t stamp = 0;
    std::vector<int32_t> left(n), right(n);
    std::function<void(int32_t)> euler = [&](int32_t u) {
        tree.emplace_back(a[u], stamp);
        left[u] = stamp++;
        for (int32_t v : adj[u])
            euler(v);
        right[u] = stamp;
    };
    for (int32_t i = 0; i < n; i++) {
        if (find(i) == i) euler(i);
    }
    for (int32_t i = n; i --> 1;)
        tree[i] = std::max(tree[i + i], tree[i + i + 1]);
    for (int32_t i = 0, j = 0; i < q; i++) {
        if (queries[i].first == 2) continue;
        int32_t l = left[queries[i].second];
        int32_t r = children[j++];
        r = (r < 0 ? l + 1 : right[r]);
        std::pair<int32_t, int32_t> res;
        for (l += n, r += n; l < r; l /= 2, r /= 2) {
            if (l & 1) res = std::max(res, tree[l++]);
            if (r & 1) res = std::max(tree[--r], res);
        }
        printf("%d\n", res.first);
        int32_t x = res.second + n;
        tree[x].first = 0;
        while (x /= 2)
            tree[x] = std::max(tree[x + x], tree[x + x + 1]);
    }
    return 0;
}

#include<bits/stdc++.h>
#define P pair<int,int>
using namespace std;
const int N=2e6;
int n,m,q;
int f[N];
int value[N/2];
P edge[N/2];
P ask[N/2];
bool split[N/2];
int l[N/2];
int r[N/2];
P tree[N];
struct nodes
{
    P s;
    P range;
    int f;
}node[N];
int cnt=0,root;
int fa(int);
void link(int,int);
void modify(int L,int R,int p,int x,int val);
P query(int l,int r,int L,int R,int p);
void dfs(int);
int main()
{
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++)scanf("%d",&value[i]),f[i]=i;//cin>>value[i],f[i]=i;
    for(int i=1;i<=m;i++)
    {
        int u,v;
        //cin>>u>>v;
        scanf("%d%d",&u,&v);
        edge[i]=P(u,v);
    }
    for(int i=1;i<=n;i++)node[++cnt].range=P(i,i),node[cnt].s=P(0,0);
    for(int i=1;i<=q;i++)
    {
        int a,b;
       // cin>>a>>b;
        scanf("%d%d",&a,&b);
        ask[i]=P(a,b);
        if(a==2)split[b]=true;
    }
    for(int i=1;i<=m;i++)if(!split[i])link(edge[i].first,edge[i].second);
    for(int i=q;i>=1;i--)
    {
        int a,b;
        a=ask[i].first;b=ask[i].second;
        if(a==2)link(edge[b].first,edge[b].second);
        else ask[i].second=fa(b);
    }
    root=cnt;
    cnt=0;
    for(int i=root;i>=1;i--)if(l[i]==0)dfs(i);
  //  for(int i=1;i<=n;i++)cout<<i<<"   : "<<l[i]<<"  -  "<<r[i]<<endl;
 //cout<<"finish dfs\n";
    for(int i=1;i<=n;i++)modify(1,cnt,1,l[i],value[i]);

    for(int i=1;i<=q;i++)
    {
        int a,b;
        a=ask[i].first;b=ask[i].second;
        if(a==2)continue;
      //  cout<<"now ask: "<<b<<endl;
        P ans=query(l[b],r[b],1,cnt,1);
        modify(1,cnt,1,ans.second,0);
      //  cout<<"  ans:  "<<ans.first<<"  pos: "<<ans.second<<endl;
      //  cout<<ans.first<<endl;
      printf("%d\n",ans.first);
    }
}

void dfs(int u)
{
  //  cout<<"in node "<<u;
    cnt++;
    l[u]=cnt;r[u]=cnt;
 //   cout<<"    cnt : "<<cnt<<endl;
    if(node[u].s==P(0,0))return;
    dfs(node[u].s.first);
    dfs(node[u].s.second);
    int v=node[u].s.second;
    r[u]=r[v];
  //  cout<<u<<"  l = "<<l[u]<<"  r = "<<r[u]<<endl;
}

int fa(int x)
{
    if(f[x]==x)return x;
    else return f[x]=fa(f[x]);
}

void link(int u,int v)
{
    u=fa(u);v=fa(v);
    if(u==v)return;
    cnt++;
    f[cnt]=cnt;f[u]=cnt;f[v]=cnt;
    node[cnt].s=P(u,v);
}

P query(int l,int r,int L,int R,int p)
{

    if(l==L&&r==R)return tree[p];
    int mid=(L+R)>>1;
    if(r<=mid)return query(l,r,L,mid,p+p);
    else if(mid+1<=l)return query(l,r,mid+1,R,p+p+1);
    else return max(query(l,mid,L,mid,p+p),query(mid+1,r,mid+1,R,p+p+1));
}

void modify(int L,int R,int p,int x,int val)
{
//cout<<L<<"  "<<R<<"  x: "<<x<<endl;
    if(L==R&&L==x)
    {
        tree[p]=P(val,L);
        return;
    }
    int mid=(L+R)>>1;
    if(x<=mid)modify(L,mid,p+p,x,val);
    else modify(mid+1,R,p+p+1,x,val);
    tree[p]=max(tree[p+p],tree[p+p+1]);
}

#include <iostream>
#include <vector>
#include <set>

using namespace std;

const int NMAX = 2e5;
const int MMAX = 3e5;
const int QMAX = 5e5;

int n, N, M, Q;
int p[NMAX + 2];

pair <int, int> edges[MMAX + 2];
set < int > edgesSet;

struct Query
{
    int type, x;
};

Query qr[QMAX + MMAX + 2];

int dad[NMAX + MMAX + 2], boss[QMAX + 2];
vector <int> g[NMAX + MMAX + 2];

int Root(int node)
{
    if(node == dad[node])
        return node;

    return dad[node] = Root(dad[node]);
}

void join(int p, int q)
{
    p = Root(p);
    q = Root(q);

    if(p != q)
    {
        ++N;
        dad[p] = N;
        dad[q] = N;

        g[N].push_back(p);
        g[N].push_back(q);
    }
}

bool vis[NMAX + MMAX + 2];
vector <int> eulerTour;

int lf[NMAX + MMAX + 2], rg[NMAX + MMAX + 2];

void dfs(int node)
{
    vis[node] = true;
    eulerTour.push_back(node);
    lf[node] = (int)eulerTour.size();

    for(auto it : g[node])
        dfs(it);

    rg[node] = (int)eulerTour.size();
}

struct Aint
{
    int v[4 * (NMAX + MMAX)];
    int p[4 * (NMAX + MMAX)];

    void Update(int node, int st, int dr, int pos, int val)
    {
        if(st == dr)
        {
            v[node] = val;
            p[node] = pos;
            return ;
        }

        int mid = (st + dr) >> 1;
        if(pos <= mid)
            Update(2 * node, st, mid, pos, val);
        else
            Update(2 * node + 1, mid + 1, dr, pos, val);

        if(v[2 * node] > v[2 * node + 1])
            v[node] = v[2 * node], p[node] = p[2 * node];
        else
            v[node] = v[2 * node + 1], p[node] = p[2 * node + 1];
    }

    pair <int, int> Query(int node, int st, int dr, int l, int r)
    {
        if(l <= st && dr <= r)
            return {v[node], p[node]};

        if(r < st || dr < l)
            return {-1, -1};

        int mid = (st + dr) >> 1;

        pair <int, int> a1 = Query(2 * node, st, mid, l, r);
        pair <int, int> a2 = Query(2 * node + 1, mid + 1, dr, l, r);

        if(a1.first > a2.first)
            return a1;

        return a2;
    }
};

Aint aint;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);

    cin >> n >> M >> Q;

    for(int i = 1; i <= n; i++)
        cin >> p[i];
    N = n;

    for(int i = 1; i <= M; i++)
    {
        int x, y;
        cin >> x >> y;
        edges[i] = {x, y};
        edgesSet.insert(i);
    }

    for(int i = 1; i <= Q; i++)
    {
        int t, x;
        cin >> t >> x;
        qr[i] = {t, x};
        if(t == 2) edgesSet.erase(x);
    }

    while(!edgesSet.empty())
    {
        int edg = *edgesSet.begin();
        edgesSet.erase(edg);
        qr[++Q] = {2, edg};
    }

    for(int i = 1; i <= N + M; i++)
        dad[i] = i;

    for(int i = Q; i >= 1; i--)
    {
        if(qr[i].type == 2)
        {
            int edg = qr[i].x;
            join(edges[edg].first, edges[edg].second);
        }
        else
            boss[i] = Root(qr[i].x);
    }

    for(int i = N; i >= 1; i--)
        if(!vis[i])
            dfs(i);

    for(int i = 1; i <= n; i++)
        aint.Update(1, 1, N, lf[i], p[i]);

    for(int i = 1; i <= Q; i++)
    {
        if(qr[i].type == 2) continue;

        pair <int, int> res = aint.Query(1, 1, N, lf[boss[i]], rg[boss[i]]);
        cout << res.first << '\n';
        aint.Update(1, 1, N, res.second, 0);
    }

    return 0;
}

#include <bits/stdc++.h>
using namespace std;
int sz[800005];
int par[800005];
int p[800005];
inline int fn(int x){
	if(par[x] == -1) return x;
	else return fn(par[x]);
}
vector<int> dsu[800005];
inline void un(int x, int y){
	x = fn(x);
	y = fn(y);
	if(x == y) return;
	if(sz[x] < sz[y]){
		swap(x, y);
	}
	sz[x] += sz[y];
	par[y] = x;
	dsu[x].push_back(y);
}
const int MAGIC = 200003;
vector<int> tour;
int st[1000005];
void dfs(int u, int p = -1){
	if(u == MAGIC-1){
		vector<int> tg;
		for(int v : dsu[u]){
			if(v == p) continue;
			tg.push_back(v);
		}
		dfs(tg[0], u);
		tour.push_back(u);
		st[u] = tour.size()-1;
		for(int i = 1; i < tg.size(); i++){
			dfs(tg[i], u);
			tour.push_back(u);
		}
	}else{
		tour.push_back(u);
		st[u] = tour.size()-1;
		for(int v : dsu[u]){
			if(v == p) continue;
			if(v >= MAGIC){
				tour.push_back(v);
				st[v] = tour.size()-1;
			}else{
				dfs(v, u);
			}
		}
	}
}
int lb[2*1048576];
int rb[2*1048576];
int seg[2*1048576];
int sidx[2*1048576];
void build(int c, int l, int r){
	lb[c] = l;
	rb[c] = r;
	if(l == r){
		seg[c] = p[tour[l]];
		sidx[c] = l;
		return;
	}
	int k = (l+r)/2;
	build(2*c, l, k);
	build(2*c+1, k+1, r);
	if(seg[2*c] < seg[2*c+1]){
		seg[c] = seg[2*c+1];
		sidx[c] = sidx[2*c+1];
	}else{
		seg[c] = seg[2*c];
		sidx[c] = sidx[2*c];
	}
}
void update(int c, int i, int x){
	if(lb[c] == rb[c]){
		seg[c] = x;
		return;
	}
	int k = (lb[c] + rb[c])/2;
	if(i <= k){
		update(2*c, i, x);
	}else{
		update(2*c+1, i, x);
	}
	if(seg[2*c] < seg[2*c+1]){
		seg[c] = seg[2*c+1];
		sidx[c] = sidx[2*c+1];
	}else{
		seg[c] = seg[2*c];
		sidx[c] = sidx[2*c];
	}
}
pair<int,int> query(int c, int l, int r){
	if(lb[c] == l && rb[c] == r) return make_pair(seg[c], sidx[c]);
	int k = (lb[c] + rb[c])/2;
	if(l <= k && k < r){
		auto p1 = query(2*c, l, k);
		auto p2 = query(2*c+1, k+1, r);
		if(p1.first < p2.first) return p2;
		else return p1;
	}else if(r <= k) return query(2*c, l, r);
	else return query(2*c+1, l, r);
}
int main(){
	memset(par, -1, sizeof(par));
	fill(sz, sz+500005, 1);
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m,q;
	cin >> n >> m >> q;
	for(int i = 1; i <= n; i++){
		cin >> p[i];
	}
	vector<pair<int,int> > edges;
	for(int i = 0; i < m; i++){
		int u, v;
		cin >> u >> v;
		edges.emplace_back(u, v);
	}
	vector<int> queries;
	set<int> isdel;
	stack<int> stk;
	for(int i = 0; i < q; i++){
		int c, x;
		cin >> c >> x;
		if(c == 1) x = -x;
		queries.push_back(x);
		if(c == 2){
			isdel.insert(x-1);
			stk.push(x-1);
		}
	}
	for(int i = 0; i < m; i++){
		if(isdel.find(i) == isdel.end()){
			un(edges[i].first, edges[i].second);
		}
	}
	while(!stk.empty()){
		int midx = stk.top();
		stk.pop();
		int f1 = fn(edges[midx].first);
		int f2 = fn(edges[midx].second);
		if(f1 == f2){
			dsu[f1].push_back(MAGIC+midx);
			par[MAGIC+midx] = f1;
			continue;
		}
		if(sz[f1] < sz[f2]){
			swap(f1, f2);
		}
		dsu[f1].push_back(MAGIC+midx);
		dsu[f1].push_back(f2);
		par[MAGIC+midx] = f1;
		par[f2] = f1;
		sz[f1] += sz[f2];
	}
	set<int> roots;
	for(int i = 1; i <= n; i++) roots.insert(fn(i));
	for(int u : roots){
		dsu[MAGIC-1].push_back(u);
		par[u] = MAGIC-1;
		sz[MAGIC-1] += sz[u];
	}
	dfs(MAGIC-1);
	build(1, 0, tour.size()-1);
	isdel.clear();
	for(int i = 0; i < tour.size(); i++){
		if(tour[i] == MAGIC-1) isdel.insert(i);
	}
	for(int i = 0; i < q; i++){
		if(queries[i] < 0){
			int x = -queries[i];
			int idx = st[x];
			int l = 0;
			auto it = isdel.lower_bound(idx);
			if(it != isdel.begin()){
				it--;
				l = *it+1;
			}
			it = isdel.upper_bound(idx);
			int r = tour.size()-1;
			if(it != isdel.end()){
				r = *it-1;
			}
			auto pr = query(1, l, r);
			update(1, pr.second, 0);
			cout << pr.first << '\n';
		}else{
			isdel.insert(st[MAGIC+queries[i]-1]);
		}
	}
	return 0;
}

#include <iostream>
#include <fstream>
#include <cstdio>

#include <vector>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <bitset>
#include <stack>

#include <functional>
#include <utility>
#include <algorithm>
#include <cmath>
#include <iterator>
#include <iomanip>

#include <cassert>
#include <random>
#include <chrono>

#include <complex>

using namespace std;

#define ll long long
#define prll pair<ll,ll>
#define m_p make_pair
#define INF (ll)1e18

const ll q = 239017;
const ll mod = 1e9 + 7;
const ll mod2 = 1e9 + 13;
const ll N = 2e5 + 100;
const ll M = 3e5 + 100;
const ll L = 26;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

ll p[N];
prll seg[N];
vector<ll> comp[N];

ll c[N];
prll qrSeg[N+M];
bitset<M> del;

ll get(ll a) {
	if (p[a] == a)
		return a;
	return p[a] = get(p[a]);
}

void merge(ll a, ll b) {
	a = get(a);
	b = get(b);
	if (a == b)return;

	if ((ll)comp[a].size() < (ll)comp[b].size())swap(a, b);

	p[b] = a;
	seg[a].second = seg[b].second;

	for (ll el : comp[b])
		comp[a].push_back(el);
	comp[b].clear();
}

struct SegTree {
	vector<ll> t,id;
	ll n;

	void update(ll v)
	{
		t[v] = max(t[v * 2], t[v * 2 + 1]);

		if (t[v * 2] > t[v * 2 + 1])
			id[v] = id[v * 2];
		else
			id[v] = id[v * 2 + 1];
	}

	void build(ll tl, ll tr, ll v, vector<ll>& a)
	{
		if (tl + 1 == tr)
		{
			t[v] = a[tl];
			id[v] = tl;
			return;
		}

		ll mid = (tl + tr) >> 1;
		build(tl, mid, v * 2, a);
		build(mid, tr, v * 2 + 1, a);

		update(v);
	}

	SegTree(vector<ll>& a)
	{
		if (a.empty())return;

		n = (ll)a.size();
		t.resize(4 * n);
		id.resize(4 * n);

		build(0, n, 1, a);
	}

	void del(ll tl, ll tr, ll v, ll k)
	{
		if (tl > k || tr <= k)return;
		if (tl + 1 == tr && tl == k)
		{
			t[v] = 0;
			return;
		}

		ll mid = (tl + tr) >> 1;
		del(tl, mid, v * 2, k);
		del(mid, tr, v * 2 + 1, k);

		update(v);
	}

	prll get_mx(ll tl, ll tr, ll v, ll l, ll r) {
		if (tr <= l || tl >= r)return { -INF, 1337 };
		if (l <= tl && tr <= r)return { t[v],id[v] };

		ll mid = (tl + tr) >> 1;
		auto a = get_mx(tl, mid, v * 2, l, r);
		auto b = get_mx(mid, tr, v * 2 + 1, l, r);

		return (a.first > b.first ? a : b);
	}

	prll get_mx(ll l, ll r)
	{
		return get_mx(0, n, 1, l, r+1);
	}
};

void $main()
{
	ll n, m, q; cin >> n >> m >> q;

	for (ll i = 0; i < n; ++i)
		cin >> c[i];

	for (ll i = 0; i < n; ++i) {
		p[i] = i;
		seg[i] = { i,i };
		comp[i].push_back(i);
	}

	vector<prll> r;
	for (ll i = 0; i < m; ++i) {
		ll a, b; cin >> a >> b;
		--a; --b;
		r.emplace_back(a, b);
	}

	vector<prll> qr;
	for (ll i = 0; i < q; ++i) {
		ll a, b; cin >> a >> b;
		--b;

		qr.emplace_back(a, b);
		if (a != 1)
			del[b] = 1;
	}

	for (ll i = 0; i < m; ++i)
		if (!del[i])
			qr.emplace_back(2, i);

	reverse(qr.begin(), qr.end());

	ll it = 0;
	for (auto el : qr) {
		if (el.first == 2) {
			merge(r[el.second].first, r[el.second].second);
		}
		else {
			qrSeg[it++] = seg[get(el.second)];
		}
	}

	for (ll i = 0; i < n; ++i)
		merge(0, i);

	//now p = pos
	ll root = get(0);
	for (ll i = 0; i < (ll)comp[root].size(); ++i)
		p[comp[root][i]] = i;

	for (ll i = 0; i < it; ++i)
		qrSeg[i] = { p[qrSeg[i].first],p[qrSeg[i].second] };

	for (ll& el : comp[root])
		el = c[el];

	SegTree tree = SegTree(comp[root]);
	for (ll i = it - 1; i >= 0; --i)
	{
		auto get = tree.get_mx(qrSeg[i].first,qrSeg[i].second);
		cout << get.first << '\n';

		tree.del(0,n,1,get.second);
	}
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("input.txt", "r", stdin);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
#endif
	ios_base::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	$main();

	return 0;
}

#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#define isz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
using li = std::list<int>;
using vi = std::vector<int>;
using vli = std::vector<li>;
using pii = std::pair<int,int>;
using vpii = std::vector<pii>;

namespace FastIO {
    struct Reader {
    private:
        FILE* file; std::vector<char> buffer; int pos; bool was;
        void read() {
            if (!buffer.empty()) {
                buffer.resize(fread(&buffer[0], 1, (int)buffer.size(), file)); pos = 0;
            }
        }
    public:
        Reader(FILE* file_ = stdin, const int size_ = 1 << 16)
            : file(file_), buffer(size_, '\0'), pos(size_), was(true) { }
        operator bool() const { return was; }
        char getChar() {
            if (pos == (int)buffer.size()) { read(); }
            if (pos == (int)buffer.size()) { was = false; return EOF; }
            else { was = true; return buffer[pos++]; }
        }
        std::string getStr() {
            char c = ' ';
            while (std::isspace(c)) { c = getChar(); }
            std::string answ;
            while (c != EOF && !std::isspace(c)) { answ.push_back(c); c = getChar(); }
            was = !answ.empty();
            return answ;
        }
        std::string getLine() {
            char c = '\n';
            while (c == '\n') { c = getChar(); }
            std::string answ;
            while (c != '\n' && c != EOF) { answ.push_back(c); c = getChar(); }
            was = !answ.empty();
            return answ;
        }
        template<typename T> T getInt() {
            char c = '?';
            while (!(c == '-' || ('0' <= c && c <= '9') || c == EOF)) { c = getChar(); }
            bool positive = true;
            if (c == '-') { positive = false; c = getChar(); }
            T answ(0);
            bool flag = false;
            while ('0' <= c && c <= '9') { flag = true; (answ *= 10) += (c - '0'); c = getChar(); }
            was = flag;
            return positive ? answ : -answ;
        }
        template<typename T> T getReal() {
            bool flag = false;
            char c = '?';
            while (!(c == '-' || ('0' <= c && c <= '9') || c == EOF)) { c = getChar(); }
            bool positive = (c != '-');
            if (c == '-') { c = getChar(); }
            long long first = 0;
            while ('0' <= c && c <= '9') { flag = true; (first *= 10) += (c - '0'); c = getChar(); }
            was = flag;
            if (c != '.') { return T(positive ? first : -first); }
            c = getChar();
            long long second = 0, pow = 1;
            while ('0' <= c && c <= '9') { (second *= 10) += (c - '0'); c = getChar(); pow *= 10; }
            T answ = first + (T)second / (T)pow;
            return positive ? answ : -answ;
        }
    };

    Reader& operator>>(Reader& reader, char& c) { return c = reader.getChar(), reader; }

    Reader& operator>>(Reader& reader, std::string& s) { return s = reader.getStr(), reader; }

    template<class T> typename std::enable_if<std::is_floating_point<T>::value, Reader&>::type
    operator>>(Reader& reader, T& t) { return t = reader.getReal<T>(), reader; }

    template<class T> typename std::enable_if<std::is_integral<T>::value, Reader&>::type
    operator>>(Reader& reader, T& t) { return t = reader.getInt<T>(), reader; }

    template<class T> Reader& operator>>(Reader& reader, std::vector<T>& vec) {
        for (auto &it : vec) { reader >> it; }
        return reader;
    }

    struct Writer {
    private:
        FILE* file; std::vector<char> buffer; int pos;
        int defaultPrecision, defaultWidth; char defaultFill;
    public:
        Writer(FILE* file_ = stdout, const int size_ = 1 << 16)
            : file(file_), buffer(size_, '\0'), pos(0), defaultPrecision(6), defaultWidth(0), defaultFill(' ') { }
        ~Writer() { flush(); }
        void flush() { putChar(EOF); }
        void setprecision(int precision) { defaultPrecision = precision; }
        void setw(int width) { defaultWidth = width; }
        void setfill(char fill) { defaultFill = fill; }
        int getPrecision() const { return defaultPrecision; }
        int getWidth() const { return defaultWidth; }
        char getFill() const { return defaultFill; }
        void putChar(char c) {
            if (pos == (int)buffer.size() || c == EOF) {
                fwrite(&buffer[0], 1, pos, file); pos = 0;
            }
            if (c != EOF) { buffer[pos++] = c; }
        }
        void putStr(const std::string& s) { for (auto it : s) putChar(it); }
        template<typename T> void putInt(T value, int width = 0, char fill = ' ') {
            bool positive = !(value < 0);
            if (value < 0) { value = -value; }
            char buf[24]; int p = 0;
            do { buf[p++] = char(value % 10 + '0'); value /= 10; } while (value > 0);
            if (!positive) { buf[p++] = '-'; }
            while (p < width) buf[p++] = fill;
            while (p > 0) putChar(buf[--p]);
        }
        template<typename T> void putReal(T value, int precision = 6, int width = 0, char fill = ' ') {
            putInt((long long)value, width - precision - 1, fill);
            value = std::abs(value-(long long)value);
            if (precision == 0) { return; }
            putChar('.');
            #define PRINT_PART(cnt, pow) \
                while (precision >= cnt) { \
                    value *= pow; \
                    putInt((int)value, cnt, '0'); \
                    value -= (int)value; \
                    precision -= cnt; \
                }
            PRINT_PART(6,1000000)
            PRINT_PART(3,1000)
            PRINT_PART(1,10)
            #undef PRINT_PART
        }
    };

    Writer& operator<<(Writer& writer, const char c) { return writer.putChar(c), writer; }

    Writer& operator<<(Writer& writer, const std::string& s) { return writer.putStr(s), writer; }

    template<class T> typename std::enable_if<std::is_floating_point<T>::value, Writer&>::type
    operator<<(Writer& writer, const T& t) {
        writer.putReal(t, writer.getPrecision(), writer.getWidth(), writer.getFill());
        return writer;
    }

    template<class T> typename std::enable_if<std::is_integral<T>::value, Writer&>::type
    operator<<(Writer& writer, const T& t) {
        writer.putInt(t, writer.getWidth(), writer.getFill());
        return writer;
    }
}

struct DSUList {
    vi par;
    vli data;
    DSUList(int n) : par(n,0),data(n,{0}) {
        for (int i = 0; i < n; i++) par[i] = i, data[i] = {i};
    }
    int getParent(int u) {
        return par[u] == u ? u : par[u] = getParent(par[u]);
    }
    void connect(int u, int v) {
        u = getParent(u);
        v = getParent(v);
        if (u == v) return;
        if (isz(data[u]) <= isz(data[v])) {
            data[v].insert(data[v].begin(),all(data[u]));
            par[u] = v;
            data[u].clear();
        } else {
            data[u].insert(data[u].end(),all(data[v]));
            par[v] = u;
            data[v].clear();
        }
    }
};
struct DSUSegs {
    vi par,start,end,sz;
    DSUSegs(int n) : par(n,0),start(n,0),end(n,0),sz(n,1) {
        for (int i = 0; i < n; i++) par[i] = i;
        // надеюсь кто-нибудь проинициализирует start извне
    }
    int getParent(int u) {
        return par[u] == u ? u : par[u] = getParent(par[u]);
    }
    int connect(int u, int v) {
        u = getParent(u);
        v = getParent(v);
        if (u == v) return isz(par);
        int lu = start[u];
        int ru = end[u];
        int lv = start[v];
        int rv = end[v];
        assert(ru == lv || rv == lu);
        if (sz[u] < sz[v]) std::swap(u,v);
        assert(sz[u] >= sz[v]);
        par[v] = u;
        sz[u] += sz[v];
        int delim = std::max(lu,lv);
        start[u] = std::min(lu,lv);
        end[u] = std::max(ru,rv);
        return delim;
    }
};
pii merge(pii a, pii b) {
    if (a.first >= b.first) return a;
    else return b;
}
struct SegTree {
    vpii data;
    SegTree(const vi& arr) : data(4 * isz(arr), pii{-1,-1}) { build(0,0,isz(arr),arr); }
    void build(int v, int l, int r, const vi& arr) {
        if (l + 1 == r) {
            data[v] = {arr[l],l};
        } else {
            int m = (l + r) / 2;
            build(2*v+1,l,m,arr);
            build(2*v+2,m,r,arr);
            data[v] = merge(data[2*v+1], data[2*v+2]);
        }
    }
    pii get(int v, int l, int r, int ql, int qr) {
        if (qr <= l || r <= ql) return pii(-1,-1);
        if (ql <= l && r <= qr) return data[v];
        int m = (l+r)/2;
        return merge(get(2*v+1,l,m,ql,qr),get(2*v+2,m,r,ql,qr));
    }
    void set(int v, int l, int r, int p, int x) {
        if (p < l || p >= r) return;
        if (l + 1 == r) {
            data[v] = {x,p};
        } else {
            int m = (l+r)/2;
            set(2*v+1,l,m,p,x);
            set(2*v+2,m,r,p,x);
            data[v] = merge(data[2*v+1], data[2*v+2]);
        }
    }
};

vi solve(const int nV, const int nE, const int nQ, vi number, vpii edges, vpii queries) {
    assert(nQ == isz(queries));
    vi willBeRemoved(nE);
    for (auto &[fi,se] : queries) {
        if (fi == 2) willBeRemoved[se] = 1;
    }
    for (int i = 0; i < nE; i++) {
        if (!willBeRemoved[i]) queries.emplace_back(2,i);
    }
    // надо найти порядок вершин который позволит при удалении ребра разбивать компоненту
    // на два непрерывных отрезка
    std::reverse(all(queries));
    DSUList dsuList(nV);
    for (auto &[fi,se] : queries) {
        if (fi == 2) {
            auto &[u,v] = edges[se];
            dsuList.connect(u,v);
        }
    }
    // вроде dsu все соединило в нужном порядке, сливаем компоненты в массив
    std::set<int> start{nV};
    vi order;
    for (int u = 0; u < nV; u++) {
        int p = dsuList.getParent(u);
        start.insert(isz(order));
        order.insert(order.end(), all(dsuList.data[p]));
        dsuList.data[p].clear();
    }
    assert(isz(order) == nV);
    vi pos(nV);
    for (int i = 0; i < nV; i++) pos[order[i]] = i;
    // вроде готово
    // надо понять как запросы будут делить непрерывные отрезки на две части
    DSUSegs dsuSegs(nV);
    for (int u = 0; u < nV; u++) {
        dsuSegs.start[u] = pos[u];
        dsuSegs.end[u] = pos[u]+1;
    }
    vi delimiters;
    for (auto &[fi,se] : queries) {
        if (fi == 2) {
            auto &[u,v] = edges[se];
            int mid = dsuSegs.connect(u,v);
            delimiters.push_back(mid);
        }
    }
    // готовы отвечать на запросы
    std::reverse(all(queries));
    vi arr(nV);
    for (int u = 0; u < nV; u++) arr[pos[u]] = number[u];
    SegTree st(arr);
    vi answer;
    for (auto &[fi,se] : queries) {
        if (fi == 1) {
            int u = se;
            auto r = start.upper_bound(pos[u]);
            assert(r != start.begin());
            auto l = std::prev(r);
            pii answ = st.get(0,0,nV,*l,*r);
            answer.push_back(answ.first);
            st.set(0,0,nV,answ.second,0);
        } else {
            start.insert(delimiters.back());
            delimiters.pop_back();
        }
    }
    return answer;
}

FastIO::Reader cin;
FastIO::Writer cout;

void readTest(int &nV, int &nE, int &nQ, vi& number, vpii& edges, vpii& queries) {
    cin >> nV >> nE >> nQ;
    number.resize(nV); for (auto & it : number) cin >> it;
    edges.resize(nE);
    for (auto &[u,v]: edges) cin >> u >> v,u--,v--;
    queries.resize(nQ);
    for (auto &[fi,se] : queries) {
        cin >> fi >> se;
        se--;
    }
    // наконец-то прочитали все данные!
}

int main() {
    int nV,nE,nQ;
    vi number;
    vpii edges, queries;
    readTest(nV,nE,nQ,number,edges,queries);
    auto answ = solve(nV,nE,nQ,number,edges,queries);
    for (auto it : answ) cout << it << '\n';
    return 0;
}

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define mp make_pair
#define pb push_back
#define VI vector<int>
#define pii pair<int,int>
using namespace std;
const int MAXN = 5e5+10;
int u[MAXN], v[MAXN], per[MAXN];
int su[MAXN], sv[MAXN];
bool rmv[MAXN];
int p[MAXN];
int n, m, q;
int qi[MAXN], val[MAXN], sz[MAXN];
int find(int x){
	if(p[x] == x) return x;
	return p[x] = find(p[x]);
}
void join(int x, int y){
	sz[find(y)] += sz[find(x)];
	p[find(x)] = find(y);
}
bool out[MAXN];
set<int> S[MAXN];
int ss;
int where[MAXN];
vector<pii> g[MAXN];
bool V[MAXN];
int vis;
void dfs(int cur, int prev, int to){
	V[cur] = true;
	where[cur] = to;
	S[to].insert(cur);
	for(int i = 0; i < (int)g[cur].size(); i++){
		int next = g[cur][i].first;
		if(next == prev) continue;
		dfs(next, cur, to);
	}
}
void dfs1(int cur, int prev, int from, int to){
	vis++;
	S[from].erase(cur);
	if(!out[cur]) S[to].insert(cur);
	else S[to].insert(0);
	where[cur] = to;
	for(int i = 0; i < (int)g[cur].size(); i++){
		if(rmv[g[cur][i].second]) continue;
		int next = g[cur][i].first;
		if(next == prev) continue;
		dfs1(next, cur, from, to);
	}
}
int main(){
	scanf("%d %d %d", &n, &m, &q);
	for(int i = 1; i <= n; i++){
		scanf("%d", &per[i]);
		p[i] = i; sz[i] = 1;
	}
	for(int i = 1; i <= m; i++){
		scanf("%d %d", &u[i], &v[i]);
		u[i] = per[u[i]];
		v[i] = per[v[i]];
	}
	for(int i = 0; i < q; i++){
		scanf("%d %d", &qi[i], &val[i]);
		if(qi[i] == 2) rmv[val[i]] = true;
		else val[i] = per[val[i]];
	}
	for(int i = 1; i <= m; i++){
		if(rmv[i]) continue;
		if(find(u[i]) == find(v[i])) continue;
		join(u[i], v[i]);
	}
	for(int i = q-1; i >= 0; i--){
		if(qi[i] == 2){
			//ru[i] = find(u[val[i]]);
			//rv[i] = find(v[val[i]]);
			int x = u[val[i]], y = v[val[i]];
			if(find(x) == find(y)){
				su[i] = sv[i] = -1;
				continue;
			}
			su[i] = sz[find(x)];
			sv[i] = sz[find(y)];
			g[x].pb(mp(y,val[i]));
			g[y].pb(mp(x,val[i]));
			join(x, y);

		}
	}
	for(int i = 1; i <= n; i++){
		p[i] = i; sz[i] = 1;
	}
	for(int i = 1; i <= n; i++){
		for(int j = 0; j < (int)g[i].size(); j++){
			int x = i, y = g[i][j].first;
			join(x, y);
		}
	}
	for(int i = 1; i <= m; i++){
		if(rmv[i]) continue;
		int x = u[i], y = v[i];
		if(find(x) == find(y)) continue;
		g[x].pb(mp(y,i)); g[y].pb(mp(x,i));
		join(x, y);
	}
	ss = 0;
	memset(V, false, sizeof V);
	for(int i = 1; i <= n; i++){
		if(!V[i]) dfs(i, i, ss++);
	}
	for(int i = 1; i <= m; i++) rmv[i] = false;
	for(int i = 0; i < q; i++){
		if(qi[i] == 1){
			int cur = val[i];
			int w = where[cur];
			int ans = *S[w].rbegin();
			printf("%d\n", ans);
			if(ans){
				out[ans] = true;
				S[w].erase(ans);
				S[w].insert(0);
			}
		}else{
			rmv[val[i]] = true;
			if(su[i] == -1) continue;
			int ei = val[i];
			if(su[i] < sv[i]){
				vis = 0;
				dfs1(u[ei], u[ei], where[u[ei]], ss++);
				if(vis != su[i]){
					printf("%d %d\n", vis, su[i]);
					return 0;
				}
			}else{
				vis = 0;
				dfs1(v[ei], v[ei], where[v[ei]], ss++);
				if(vis != sv[i]){
					printf("%d %d\n", vis, sv[i]);
					return 0;
				}
			}
		}
	}
	return 0;
}

/*mjytxdy!*/
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define fir first
#define sec second
#define all(x) x.begin(),x.end()
#define size(x) ((int)x.size())
#define pii pair<int,int>
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pll pair<ll,ll>
#define inl inline
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,r,l) for(int i=(r);i>=(l);i--)
#define trv(i,u) for(int i=head[u];i;i=e[i].next)
#define lb(x) ((x)&(-(x)))
#define lson rt<<1
#define rson rt<<1|1
#define debug(x) cout<<#x":"<<x<<'\n'
#define myput puts("QaQ")
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
typedef long long ll;
template<class T>inl bool ylmin(T &a,T b){return a<b?0:(a=b,1);}
template<class T>inl bool ylmax(T &a,T b){return a>b?0:(a=b,1);}
template<class T>inl T abs(T x){return x<0?-x:x;}
inl char read(){
	static const int IO_LEN=1024*1024;
	static char buf[IO_LEN],*ioh,*iot;
	if(ioh==iot){
		iot=(ioh=buf)+fread(buf,1,IO_LEN,stdin);
		if(ioh==iot) return -1;
	}
	return *ioh++;
}
template<class T>inl void read(T &x){
	static int iosig;static char ioc;
	for(iosig=0,ioc=read();!isdigit(ioc);ioc=read()) if(ioc=='-') iosig=1;
	for(x=0;isdigit(ioc);ioc=read())x=(x<<1)+(x<<3)+(ioc^'0');
	if(iosig) x=-x;
}
const int MAXN = 5e5+10;
int n,m,Q,p[MAXN],rev[MAXN],is[MAXN];
int Nodecnt,ls[MAXN],rs[MAXN];
int top[MAXN];
struct Edge{
	int u,v;
}e[MAXN];
struct que{
	int opt,x;
}q[MAXN];
namespace ufs{
	int fa[MAXN];
	inl void clear(){
		rep(i,1,n<<1) fa[i]=i;
	}
	inl int find(int x){
		return fa[x]==x?x:fa[x]=find(fa[x]);
	}
}
int dfs_time,L[MAXN],R[MAXN];
inl void dfs(int u){
	if(u<=n) L[u]=R[u]=++dfs_time,rev[dfs_time]=p[u];
	else {
		//cout<<u<<":"<<ls[u]<<' '<<rs[u]<<'\n';
		L[u]=dfs_time+1;
		dfs(ls[u]),dfs(rs[u]);
		R[u]=dfs_time;
	}
}
namespace seg{
	int Max[MAXN<<1],pos[MAXN<<1];
	inl void pushup(int rt){
		if(Max[lson]<Max[rson]) Max[rt]=Max[rson],pos[rt]=pos[rson];
		else Max[rt]=Max[lson],pos[rt]=pos[lson];
	}
	inl void update(int rt,int l,int r,int k){
		if(l==r){
			Max[rt]=0;
			return ;
		}
		int mid=l+r>>1;
		if(k<=mid) update(lson,l,mid,k);
		else update(rson,mid+1,r,k);
		pushup(rt);
	}
	inl pii query(int rt,int l,int r,int L,int R){
		if(l>=L && r<=R) return {Max[rt],pos[rt]};
		int mid=l+r>>1;
		if(R<=mid) return query(lson,l,mid,L,R);
		else if(L>mid) return query(rson,mid+1,r,L,R);
		else return max(query(lson,l,mid,L,R),query(rson,mid+1,r,L,R));
	}
	inl void build(int rt,int l,int r){
		if(l==r){
			pos[rt]=l;
			Max[rt]=rev[l];
			return ;
		}
		int mid=l+r>>1;
		build(lson,l,mid),build(rson,mid+1,r);
		pushup(rt);
	}
}
int main(){
//	freopen("in.txt","r",stdin);
	read(n),read(m),read(Q);Nodecnt=n;
	rep(i,1,n) read(p[i]);
	rep(i,1,m) read(e[i].u),read(e[i].v);
	rep(i,1,Q) read(q[i].opt),read(q[i].x);
	rep(i,1,Q) if(q[i].opt==2) is[q[i].x]=1;
	ufs::clear();
	rep(i,1,m){
		if(!is[i]) {
			int x=ufs::find(e[i].u),y=ufs::find(e[i].v);
			//cout<<e[i].u<<' '<<e[i].v<<'\n';
			if(x==y) continue;
			ufs::fa[x]=ufs::fa[y]=++Nodecnt;
			ls[Nodecnt]=x,rs[Nodecnt]=y;
		}
	}
	per(i,Q,1){
		if(q[i].opt==1){
			int x=ufs::find(q[i].x);
			top[i]=x;
		}
		if(q[i].opt==2){
			int x=ufs::find(e[q[i].x].u),y=ufs::find(e[q[i].x].v);
			//cout<<e[q[i].x].u<<' '<<e[q[i].x].v<<'\n';
			if(x==y) continue;
			ufs::fa[x]=ufs::fa[y]=++Nodecnt;
			ls[Nodecnt]=x,rs[Nodecnt]=y;
		}
	}
	int last=0;
	rep(i,1,Nodecnt) {
		if(ufs::find(i)==i) {
			if(last){
				ufs::fa[i]=ufs::fa[last]=++Nodecnt;
				ls[Nodecnt]=i,rs[Nodecnt]=last;
				last=0;
			}
			else last=i;
		}
	}
	dfs(Nodecnt);
	seg::build(1,1,n);
	rep(i,1,Q){
		if(q[i].opt==1){
			//cout<<top[i]<<":";
			pii Max=seg::query(1,1,n,L[top[i]],R[top[i]]);
			printf("%d\n",Max.fir);
			seg::update(1,1,n,Max.sec);
		}
	}
	return 0;
}

#include <cstdlib>
#include <cmath>
#include <climits>
#include <cfloat>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <sstream>
#include <deque>
#include <complex>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <ctime>
#include <iterator>
#include <bitset>
#include <numeric>
#include <list>
#include <iomanip>
#include <cassert>
#include <functional>
#include <unordered_map>
#include <unordered_set>
#include <queue>
using namespace std;
#define x first
#define y second
#define mp make_pair
#define pb push_back
#define div div228
#define prev prev228
#define free free228
#define close close228
typedef long double ld;
const int BINF = 9e18, LINF = 2e9, mod = 1e9 + 7, P = 179, Q = 1791791791;
typedef long long ll;

const int MAXN = 6e5 + 6, MAXQ = 1e6 + 6;
int a[MAXN], b[MAXN], p[MAXN];
list<int> cmp[MAXN];
int par[MAXN];
int t[MAXQ], f[MAXQ];
bool ban[MAXN];
int sep[MAXN];
int pos[MAXN], who[MAXN];
int get(int v) {
	if (par[v] == v)
		return v;
	return par[v] = get(par[v]);
}
int merge(int v, int u) {
	v = get(v), u = get(u);
	if (v == u)
		return -1;
	par[u] = v;
	int ans = *cmp[u].begin();
	cmp[v].splice(cmp[v].end(), cmp[u]);
	return ans;
}
pair<int, int> tt[4 * MAXN];
void build(int v, int tl, int tr) {
	if (tl == tr) {
		int val = p[who[tl]];
		tt[v] = {val, who[tl]};
	} else {
		int tm = (tl + tr) / 2;
		build(v << 1, tl, tm);
		build(v << 1 ^ 1, tm + 1, tr);
		tt[v] = max(tt[v << 1], tt[v << 1 ^ 1]);
	}
}
pair<int, int> get(int v, int tl, int tr, int l, int r) {
	if (l > tr || tl > r)
		return {-1, -1};
	if (l <= tl && tr <= r)
		return tt[v];
	int tm = (tl + tr) / 2;
	return max(get(v << 1, tl, tm, l, r), get(v << 1 ^ 1, tm + 1, tr, l, r));
}
void upd(int v, int tl, int tr, int p, int x) {
	if (tl == tr)
		tt[v] = {x, who[tl]};
	else {
		int tm = (tl + tr) / 2;
		if (p <= tm)
			upd(v << 1, tl, tm, p, x);
		else
			upd(v << 1 ^ 1, tm + 1, tr, p, x);
		tt[v] = max(tt[v << 1], tt[v << 1 ^ 1]);
	}
}
void solve() {
    int n, m, q;
    cin >> n >> m >> q;
    for (int i = 0; i < n; ++i)
    	cin >> p[i], par[i] = i, cmp[i].push_back(i);
    for (int i = 0; i < m; ++i) {
  		cin >> a[i] >> b[i];
  		--a[i], --b[i];
    }
    for (int i = 0; i < q; ++i) {
    	cin >> t[i] >> f[i];
    	--f[i];
    }
    for (int i = q - 1; i >= 0; --i)
    	if (t[i] == 2)
    		ban[f[i]] = 1;
    for (int i = 0; i < m; ++i)
    	if (!ban[i])
    		merge(a[i], b[i]);
    for (int i = q - 1; i >= 0; --i)
    	if (t[i] == 2)
    		sep[i] = merge(a[f[i]], b[f[i]]);
    int ptr = 0;
    set<pair<int, int>> segs;
    for (int i = 0; i < n; ++i)
    	if (par[i] == i) {
    		int l = ptr;
    		for (int v : cmp[i]) {
    			who[ptr] = v;
    			pos[v] = ptr++;
    		}
    		int r = ptr - 1;

    		segs.insert({l, r});
    	}
    build(1, 0, n - 1);
    /*cout << "#" << ptr << endl;
    cout << "=====\n";
    for (auto p : segs)
    	cout << p.x << "; " << p.y << endl;
    cout << "=====\n";*/
    for (int i = 0; i < q; ++i) {
    	if (t[i] == 2) {
    		if (sep[i] != -1) {
    			int m = pos[sep[i]];
    			auto it = segs.lower_bound({m, 1e9});
    			--it;
    			int l = it->x;
    			int r = it->y;
    			segs.erase(it);
    			segs.insert({l, m - 1});
    			segs.insert({m, r});
    		}
    	} else {
    		int v = f[i];
    		auto it = segs.lower_bound({pos[v], 1e9});
			--it;
			int l = it->x;
			int r = it->y;
			pair<int, int> pr = get(1, 0, n - 1, l, r);
			upd(1, 0, n - 1, pos[pr.second], 0);
			cout << pr.first << "\n";
    	}
    }
    return;
}
signed main() {
	//freopen("in.txt", "r", stdin);
    ios_base::sync_with_stdio(false);
    //cout.precision(40);

    int t = 1;
    //cin >> t;
    for (int i = 0; i < t; ++i)
        solve();

    return 0;
}
/*

10 5 15
1 2 3 4 5 6 7 8 9 10
1 2
3 4
5 6
7 8
9 10
1 1
2 1
1 1
1 3
2 2
1 3
1 5
2 3
1 5
1 7
2 4
1 8
1 9
2 5
1 10
*/

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char buf[2000005];
int pt=2000000;
char gc(){
	if(pt>=2000000)fread(buf,1,2000000,stdin),pt=0;
	return buf[pt++];
}
int rd(){
	int x=0,ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))x=x*10+ch-'0',ch=gc();
	return x;
}
struct Query{
	int opt,x,rx,ry;
}q[500005];
int n,m,Q,fa[200005],ex[300005],ey[300005],del[300005],sz[300005],bel[200005],a[200005],used[200005];
vector<int> h[200005];
vector<int> vec[200005];
int gf(int x){
	return fa[x]==x?x:gf(fa[x]);
}
int Query(int x){
	while(h[x].size()&&(bel[h[x].back()]!=x||used[h[x].back()]))h[x].pop_back();
	if(!h[x].size())return 0;
	int r=h[x].back();
	return h[x].pop_back(),used[r]=1,r;
}
int main() {
	n=rd(),m=rd(),Q=rd();
	for(int i=1,x;i<=n;i++)x=rd(),h[fa[i]=i].push_back(a[i]=x),sz[i]=1;
	for(int i=1;i<=m;i++)ex[i]=rd(),ey[i]=rd();
	for(int i=1;i<=Q;i++){
		q[i].opt=rd(),q[i].x=rd();
		if(q[i].opt==2)del[q[i].x]=1;
	}
	for(int i=1;i<=m;i++){
		if(del[i])continue;
		int x=gf(ex[i]),y=gf(ey[i]);
		if(x==y)continue;
		if(sz[x]>sz[y])swap(x,y);
		for(int j:h[x])h[y].push_back(j);
		fa[x]=y,sz[y]+=sz[x];
	}
	for(int i=Q;i>=1;i--){
		int x=ex[q[i].x],y=ey[q[i].x];
		if(q[i].opt==1||gf(x)==gf(y))continue;
		x=gf(x),y=gf(y);
		if(sz[x]>sz[y])swap(x,y);
		q[i].rx=x,q[i].ry=y,fa[x]=y,sz[y]+=sz[x];
		for(int j:h[x])h[y].push_back(j);
	}
	for(int i=1;i<=n;i++){
		for(int j:h[i])vec[j].push_back(i);
		h[i].clear();
	}
	for(int i=1;i<=n;i++)for(int j:vec[i])h[j].push_back(i);
	for(int i=1;i<=n;i++)bel[a[i]]=gf(i);
	for(int i=1,u;i<=Q;i++){
		if(q[i].opt==1)printf("%d\n",u=Query(gf(q[i].x)));
		else if(q[i].rx){
			for(int j:h[q[i].rx])bel[j]=q[i].rx;
			fa[q[i].rx]=q[i].rx;
		}
	}
	return 0;
}

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <cmath>
#include <map>
#include <queue>
#include <iomanip>
#include <set>
#include <tuple>
#define mkp make_pair
#define mkt make_tuple
#define rep(i,n) for(int i = 0; i < (n); ++i)
#define all(v) v.begin(),v.end()
using namespace std;
typedef long long ll;
const ll MOD=1e9+7;
template<class T> void chmin(T &a,const T &b){if(a>b) a=b;}
template<class T> void chmax(T &a,const T &b){if(a<b) a=b;}

class DisjointSet{
public:
  int N;
  vector<int> rank,p;
  vector<int> sz;

  vector<set<int>> vse;
  vector<int> P;
  vector<pair<int,int>> undo_pair;

  DisjointSet(){}
  DisjointSet(int n,vector<int> P,int TL):N(n),rank(n),p(n),sz(n),P(P),vse(n){
    for(int i=0;i<N;i++) makeSet(i);
    undo_pair.resize(TL,mkp(-1,-1));
  }

  void makeSet(int x){
    p[x]=x;
    rank[x]=0;
    sz[x]=1;
    vse[x].insert(P[x]);
  }

  bool same(int x,int y){
    return leader(x)==leader(y);
  }

  void unite(int x,int y,int t){
    if(same(x,y)) return;
    link(leader(x),leader(y),t);
  }

  void link(int x,int y,int t){
    if(sz[x]>sz[y]) swap(x,y);

    undo_pair[t]=mkp(x,y);
    p[x]=y;
    sz[y]+=sz[x];
    for(auto s:vse[x]) vse[y].insert(s);
    /*if(rank[x]==rank[y]){
      ++rank[y];
    }*/
  }

  int leader(int x){
    if(x!=p[x]){
      return leader(p[x]);
    }
    return p[x];
  }

  int size(int x){
    return sz[leader(x)];
  }

  void undo(int t){
    if(undo_pair[t]==mkp(-1,-1)) return;
    int x,y;
    tie(x,y)=undo_pair[t];
    for(auto s:vse[x]) vse[y].erase(s);
    p[x]=x;
  }
};

int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);

  int N,M,Q;
  cin>>N>>M>>Q;
  vector<int> P(N);
  rep(i,N) cin>>P[i];
  vector<int> A(M),B(M);
  rep(i,M) cin>>A[i]>>B[i];

  rep(i,N) P[i]--;
  rep(i,M){
    A[i]--;B[i]--;
  }
  vector<pair<int,int>> qry(Q);
  rep(i,Q){
    int t,v;
    cin>>t>>v;
    v--;
    qry[i]=mkp(t,v);
  }

  vector<int> exi(M,0);
  rep(i,Q) if(qry[i].first==2) exi[qry[i].second]=1;

  DisjointSet us(N,P,Q+10);
  rep(i,M) if(exi[i]==0) us.unite(A[i],B[i],Q);
  for(int i=Q-1;i>=0;i--){
    if(qry[i].first==2){
      int t=qry[i].second;
      us.unite(A[t],B[t],i);
    }
  }

  vector<int> used(N+1,0);
  vector<int> ans;
  for(int i=0;i<Q;i++){
    int t,v;
    tie(t,v)=qry[i];
    if(t==1){
      int res=-1;
      int p=us.leader(v);
      while(us.vse[p].size()){
        auto itr=us.vse[p].end();
        --itr;
        int val=*itr;
        us.vse[p].erase(itr);
        if(used[val]==0){
          used[val]=1;
          res=val;
          break;
        }
      }
      ans.push_back(res);
    }else{
      us.undo(i);
    }
  }

  for(auto n:ans) cout<<n+1<<"\n";

  return 0;
}

// Nurstan Duisengaliev
// ASA KONKRETNO KATAIMASH
// MUKHA KONKRETNO KATAIMASH
// ADIL SEN KATAIABER, TEBE MOZHNO

/*#pragma GCC target ("avx2")
#pragma GCC optimize ("Ofast")
#pragma GCC optimize ("unroll-loops")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimize("O3")*/

#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

#define ll long long
#define all(x) x.begin(), x.end()
#define in insert
#define mp make_pair
#define F first
#define S second
#define ppf pop_front
#define pb push_back
#define ppb pop_back
#define pf push_front
#define pii pair <int, int>
#define boost() ios_base::sync_with_stdio(0), cin.tie(0)
#define sz(x) (int)x.size()

using namespace std;
//using namespace __gnu_pbds;

//template<typename T> using ordered_set = tree <T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

const int N = (int)4e6 + 123;
const int mod = (int)1e9 + 7;
const ll INF = (ll)1e18 + 1;
int n, m, Q;
int a[N], par[N];
pii edge[N], q[N];
bool del[N];
vector <int> g[N];
int get_par (int v) {
	if (par[v] == v) return v;
	return par[v] = get_par (par[v]);
}
void unite_sets (int v, int u) {
	v = get_par (v), u = get_par (u);
	if (v == u) return;
	n ++;
	par[v] = n;
	par[u] = n;
	par[n] = n;
	g[n].pb (v);
	g[n].pb (u);
}
int tin[N], tout[N], timer = 0;
pii d[N];
void update (int v, int l, int r, int pos, pii x) {
	if (l == r) {
		d[v] = x;
		return;
	}
	int mid = l + r >> 1;
	if (pos <= mid) update (v * 2, l, mid, pos, x);
	else update (v * 2 + 1, mid + 1, r, pos, x);
	if (d[v * 2].F <= d[v * 2 + 1].F) d[v] = d[v * 2 + 1];
	else d[v] = d[v * 2];
}
pii get (int v, int l, int r, int nl, int nr) {
	if (nl > r || l > nr) return mp (0, 0);
	if (nl <= l && r <= nr) return d[v];
	int mid = l + r >> 1;
	pii f = get (v * 2, l, mid, nl, nr), s = get (v * 2 + 1, mid + 1, r, nl, nr);
	if (f.F >= s.F) return f;
	else return s;
}
void dfs (int v) {
	tin[v] = ++ timer;
	update (1, 1, n, tin[v], mp (a[v], tin[v]));
	for (auto to : g[v]) {
		dfs (to);
	}
	tout[v] = timer;
}
void solve () {
	cin >> n >> m >> Q;
	for (int i = 1; i <= n; i ++) {
		cin >> a[i];
		par[i] = i;
	}
	for (int i = 1; i <= m; i ++) {
		cin >> edge[i].F >> edge[i].S;
	}
	for (int i = 1; i <= Q; i ++) {
		int x, y;
		cin >> x >> y;
		q[i] = mp (x, y);
		if (x == 2) {
			del[y] = 1;
		}
	}
	for (int i = 1; i <= m; i ++) {
		if (!del[i]) unite_sets (edge[i].F, edge[i].S);
	}
	for (int i = Q; i >= 1; i --) {
		if (q[i].F == 1) {
			q[i].S = get_par (q[i].S);
		}
		else {
			unite_sets (edge[q[i].S].F, edge[q[i].S].S);
		}
	}
	for (int i = 1; i <= n; i ++) {
		if (par[i] == i) {
			dfs (i);
		}
	}
	for (int i = 1; i <= Q; i ++) {
		if (q[i].F == 1) {
			pii x = get (1, 1, n, tin[q[i].S], tout[q[i].S]);
			if (x.F != 0) update (1, 1, n, x.S, mp (0, 0));
			cout << x.F << '\n';
		}
	}
}

main () {
//	freopen (".in", "r", stdin);
//	freopen (".out", "w", stdout);
	boost ();
	int TT = 1;
// 	cin >> TT;
	while (TT --) {
		solve ();
	}
	return 0;
}

#include <algorithm>
#include <cstdio>
using namespace std;
int const maxn = 400003;
int n = 0, m = 0, q = 0, cPoint = 0;
int p[maxn];
struct Edge {
	int u, e;
	int id;
};
Edge E[maxn];
int deleteTime[maxn];
inline bool operator<(Edge const &lhs, Edge const &rhs) { return deleteTime[lhs.id] > deleteTime[rhs.id]; }

int opt[500003], Sec[500003];

int head[maxn], nxt[maxn], to[maxn], cnt = 0;
inline void insert(int u, int e) {
	nxt[++cnt] = head[u];
	head[u] = cnt;
	to[cnt] = e;
}

int fath[maxn];
inline int find(int x) { return fath[x] == x ? x : fath[x] = find(fath[x]); }
int ti[maxn];
void CreateTheTree() {
	std::sort(E + 1, E + m + 1);
	for (int i = 1; i <= 2 * n; ++i)
		fath[i] = i;
	cPoint = n;
	for (int i = 1; i <= m; ++i) {
		if (find(E[i].u) == find(E[i].e)) continue;
		++cPoint;
		ti[cPoint] = deleteTime[E[i].id];
		insert(cPoint, find(E[i].u));
		insert(cPoint, find(E[i].e));
		fath[find(E[i].u)] = cPoint;
		fath[find(E[i].e)] = cPoint;
	}
}

int fa[20][maxn], Ldfn[maxn], Rdfn[maxn];
int dfn[maxn], idfn[maxn];
void dfs(int x, int f) {
	fa[0][x] = f;
	for (int j = 1; j <= 18; ++j)
		fa[j][x] = fa[j - 1][fa[j - 1][x]];
	if (x <= n) {
		Ldfn[x] = Rdfn[x] = dfn[x] = ++dfn[0];
		idfn[dfn[x]] = x;
		return;
	}
	Ldfn[x] = cPoint + 1, Rdfn[x] = 0;
	for (int i = head[x]; i; i = nxt[i]) {
		dfs(to[i], x);
		Ldfn[x] = std::min(Ldfn[x], Ldfn[to[i]]);
		Rdfn[x] = std::max(Rdfn[x], Rdfn[to[i]]);
	}
}

struct MX {
	int v, pos;
};
MX operator|(MX const &lhs, MX const &rhs) { return lhs.v > rhs.v ? lhs : rhs; }
MX mx[maxn << 2];
void CreateSeg(int po, int L, int R) {
	if (L == R) {
		mx[po].v = p[idfn[L]];
		mx[po].pos = idfn[L];
		return;
	}
	int mid = (L + R) >> 1;
	CreateSeg(po << 1, L, mid);
	CreateSeg(po << 1 | 1, mid + 1, R);
	mx[po] = mx[po << 1] | mx[po << 1 | 1];
}
void Modify(int po, int L, int R, int x) {
	if (L == R) {
		mx[po].v = p[idfn[L]];
		return;
	}
	int mid = (L + R) >> 1;
	if (x <= mid)
		Modify(po << 1, L, mid, x);
	else
		Modify(po << 1 | 1, mid + 1, R, x);
	mx[po] = mx[po << 1] | mx[po << 1 | 1];
}
MX query(int po, int L, int R, int l, int r) {
	if (l <= L && R <= r)
		return mx[po];
	int mid = (L + R) >> 1;
	if (r <= mid)
		return query(po << 1, L, mid, l, r);
	else if (l > mid)
		return query(po << 1 | 1, mid + 1, R, l, r);
	else
		return query(po << 1, L, mid, l, r) | query(po << 1 | 1, mid + 1, R, l, r);
}

int jump(int x, int time) {
	for (int j = 18; ~j; --j)
		if (ti[fa[j][x]] > time)
			x = fa[j][x];
	return x;
}
int main() {
	scanf("%d %d %d", &n, &m, &q);
	for (int i = 1; i <= n; ++i)
		scanf("%d", p + i);
	for (int i = 1; i <= m; ++i) {
		scanf("%d %d", &E[i].u, &E[i].e);
		E[i].id = i;
		deleteTime[i] = q + 1;
	}
	for (int i = 1; i <= q; ++i) {
		scanf("%d %d", opt + i, Sec + i);
		if (opt[i] == 2) deleteTime[Sec[i]] = i;
	}
	CreateTheTree();
	for (int i = 1; i <= cPoint; ++i)
		if (fath[i] == i) dfs(i, 0);
	CreateSeg(1, 1, n);

	for (int i = 1; i <= q; ++i)
		if (opt[i] == 1) {
			int x = jump(Sec[i], i);
			MX res = query(1, 1, n, Ldfn[x], Rdfn[x]);
			printf("%d\n", res.v);
			p[res.pos] = 0;
			Modify(1, 1, n, dfn[res.pos]);
		}
	return 0;
}

#include<bits/stdc++.h>
using namespace std ;

#define ll int
#define pb push_back
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define memf(a) memset(a,false,sizeof(a))
#define all(v) v.begin(),v.end()
#define sz(a) (ll)a.size()
#define F first
#define S second
#define INF 2000000000000000000
#define endl "\n"
#define _time_ 1.0 * clock() / CLOCKS_PER_SEC
#define popcount(x) __builtin_popcountll(x)
#define pll pair<ll,ll>
#define ld long double

const int M=1000000007;
const int MM=998244353;
const long double PI = acos(-1);

ll power(ll b,ll e,ll m)
{
    if(e==0) return 1;
    if(e&1) return b*power(b*b%m,e/2,m)%m;
    return power(b*b%m,e/2,m);
}
ll power( ll b, ll e)
{
    if(e==0) return 1;
    if(e&1) return b*power(b*b,e/2);
    return power(b*b,e/2);
}
template<typename T, typename U> static inline void amin(T &x, U y){ if(y<x) x=y; }
template<typename T, typename U> static inline void amax(T &x, U y){ if(x<y) x=y; }
template<typename T, typename U> ostream& operator<<(ostream &os, const pair<T, U> &p)
{
    return os<<'('<<p.F<< ","<<p.S<<')';
}

const int N = 200005;
const int LOGN = 19;
int val[N];

struct node
{
    ll mx,idx;
}fake{-N,-1};
    // base value is assigned to fake node
struct SEGTREE
{
    ll a[N];
    SEGTREE(){ mem0(a); }
    node tree[4*N];
    ll lazy[4*N];
    inline node combine(node a,node b)
    {
        node ret;
        ret.mx=max(a.mx,b.mx);
        if(ret.mx == a.mx)
            ret.idx = a.idx;
        else
            ret.idx = b.idx;
        return ret;
    }
    inline node make_node(ll val,ll st)
    {
        node ret;
        ret.mx=val;
        ret.idx = st;
        return ret;
    }
    void buildTree(ll v,ll st,ll en)
    {
        if(st==en)
        {
            tree[v]=make_node(a[st],st);
            return ;
        }
        ll mid=(st+en)>>1;
        buildTree(v<<1,st,mid);
        buildTree(v<<1 | 1,mid+1,en);
        tree[v]=combine(tree[v<<1],tree[v<<1 | 1]);
    }
    void update(ll v,ll st,ll en,ll in,ll val)
    {
        ll mid=(st+en)>>1;
        if(st==en)
        {
            tree[v]=make_node(val,st);
            a[st]=val;
            return ;
        }
        if(in<=mid)
            update(v<<1,st,mid,in,val);
        else
            update(v<<1 | 1,mid+1,en,in,val);
        tree[v]=combine(tree[v<<1],tree[v<<1 | 1]);
    }
    node query(ll v,ll st,ll en,ll l,ll r)
    {
        if(en<l || st>r)
            return fake;
        if(st>=l && en<=r)
            return tree[v];
        ll mid=(st+en)>>1;
        return combine(query(v<<1,st,mid,l,r),query(v<<1 | 1,mid+1,en,l,r));
    }
}seg;

struct dsu_tree
{
    vector<int> pos,idx,par,rnk,par_node;
    int cur = 0,indexing=0;
    int root = -1;
    struct dsu_node
    {
        int l,r,L,R,v;
        int p[LOGN];
        ll w;
        dsu_node():L(-1), R(-1), w(0), v(-1),l(-1),r(-1){}
    };
    vector<dsu_node> tr;

    dsu_tree(int n): cur(0), indexing(0), root(-1)
    {
        pos.resize(n+1);
        idx.resize(n+1);
        par_node.resize(n+1);
        par.resize(n+1);
        tr.resize(2*n+2);
        rnk.resize(n+1);
        for(int i=0;i<=n;++i)
            rnk[i] = 0,par[i] = i;
        for(int i=1;i<=n;++i)
        {
            int x = getNode();
            tr[x].v = i;
            assert(x==i-1);
            par_node[i] = x;
        }
    }
    int parent(int i)
    {
        return par[i] = (par[i]==i)?i:parent(par[i]);
    }
    int getNode()
    {
        int v = cur ++;
        tr[v] = dsu_node();
        return v;
    }
    void merge(int x,int y,ll w)
    {
        x = parent(x),y = parent(y);
        if(x == y)
            return ;
        int u = getNode();
        tr[u].w = w;
        tr[u].L = par_node[x];
        tr[u].R = par_node[y];
        if(rnk[x]>rnk[y])
            par[y] = x,par_node[x] = u;
        else
            par[x] = y,par_node[y] = u;
        if(rnk[x] == rnk[y])
            ++rnk[y];

    }
    void dfs(int s)
    {
        for(int j=1;j<LOGN;++j)
            tr[s].p[j] = tr[tr[s].p[j-1]].p[j-1];
        if(tr[s].v != -1)
        {
            idx[tr[s].v] = indexing;
            pos[indexing] = tr[s].v;
            tr[s].l = tr[s].r = indexing;
            ++indexing;
        }
        if(tr[s].L != -1)
        {
            tr[tr[s].L].p[0] = s;
            tr[tr[s].R].p[0] = s;
            dfs(tr[s].L);
            dfs(tr[s].R);
            tr[s].l = tr[tr[s].L].l;
            tr[s].r = tr[tr[s].R].r;
        }
    }
    void dfs()
    {
        root = cur - 1;
        tr[root].p[0] = root;
        dfs(root);
    }
    pair<int,int> lift(int u,ll w)
    {
        u = u-1;
        for(int j=LOGN-1;j>=0;--j)
        {
            // change here
            if(tr[tr[u].p[j]].w>=w)
                u = tr[u].p[j];
        }
        return make_pair(tr[u].l,tr[u].r);
    }
};
// in case of tree call dsu.dfs()
// else call for every component
// 0 based
// number at index i --> pos[i]

int _runtimeTerror_()
{
    int n,m,q;
    cin>>n>>m>>q;
    for(int i=1;i<=n;++i)
        cin>>val[i];
    vector<pair<int,int>> query,edges(m);
    vector<int> mark(m,10*N),in(m);
    for(int i=0;i<m;++i)
    {
        in[i] = i;
        cin>>edges[i].F>>edges[i].S;
    }
    for(int i=0;i<q;++i)
    {
        int tt,u;
        cin>>tt>>u;
        query.pb({tt,u});
        if(tt==2)
            mark[u-1] = i;
    }
    sort(all(in),[&](int x,int y){
        return mark[x]>mark[y];
    });
    dsu_tree dsu(n);
    for(auto &j:in)
    {
        dsu.merge(edges[j].F,edges[j].S,mark[j]);
    }
    vector<bool> vis(n+1,false);
    for(int i=1;i<=n;++i)
    {
        int x =dsu.parent(i);
        if(vis[x])
            continue;
        vis[x] =true;
        int root = dsu.par_node[x];
        dsu.tr[root].p[0] =root;
        dsu.dfs(root);
    }
    for(int i=1;i<=n;++i)
        seg.a[dsu.idx[i]] = val[i];
    seg.buildTree(1,0,n-1);
    for(int i=0;i<q;++i)
    {
        if(query[i].F==2)
            continue;
        pair<int,int> range = dsu.lift(query[i].S,i);
        node u = seg.query(1,0,n-1,range.F,range.S);
        cout<<u.mx<<"\n";
        seg.update(1,0,n-1,u.idx,0);
    }
    return 0;
}

int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    #ifdef runSieve
        sieve();
    #endif
    #ifdef NCR
        initialize();
    #endif
    int TESTS=1;
    // cin>>TESTS;
    while(TESTS--)
        _runtimeTerror_();
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
int Read() {
    int x = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-')  f = -1; ch = getchar();}
    while(isdigit(ch)) {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar();}
    return x * f;
}
int first[800005], nxt[800005], to[800005], tot = 0;
void Add(int x, int y) {
    nxt[++tot] = first[x];
    first[x] = tot;
    to[tot] = y;
}
int ex[500005], ey[500005], vis[500005], rt[500005], tag[500005];
int sz[500005], bh[500005], a[500005], opt[500005], x[500005], vvis[500005], maxn[500005], minn[500005];
int L[500005], R[500005], rev[500005], mx[2000005], Pos[2000005];
void pushup(int o) {
    if(mx[o << 1] > mx[o << 1 | 1])  mx[o] = mx[o << 1], Pos[o] = Pos[o << 1];
    else  mx[o] = mx[o << 1 | 1], Pos[o] = Pos[o << 1 | 1];
}
void build(int o, int l, int r) {
    if(l == r) {mx[o] = a[rev[l]]; Pos[o] = l; return ;}
    int mid = (l + r) >> 1;
    build(o << 1, l, mid);
    build(o << 1 | 1, mid + 1, r);
    pushup(o);
}
void modify(int o, int l, int r, int pos, int val) {
    if(l == r) {mx[o] = val; return ;}
    int mid = (l + r) >> 1;
    if(pos <= mid)  modify(o << 1, l, mid, pos, val);
    else  modify(o << 1 | 1, mid + 1, r, pos, val);
    pushup(o);
}
pair<int, int> my_max(pair<int, int> A, pair<int, int> B) {
    return (A.first > B.first) ? A : B;
}
pair<int, int> query(int o, int l, int r, int nl, int nr) {
    if(nl <= l && r <= nr)  return make_pair(mx[o], Pos[o]);
    int mid = (l + r) >> 1; pair<int, int> ans;
    ans.first = ans.second = 0;
    if(nl <= mid)  ans = my_max(ans, query(o << 1, l, mid, nl, nr));
    if(mid < nr)  ans = my_max(ans, query(o << 1 | 1, mid + 1, r, nl, nr));
    return ans;
}
int findfa(int x) {return rt[x] == x ? x : rt[x] = findfa(rt[x]);}
void dfs(int u) {
    vvis[u] = 1;
    bh[u] += tag[u];
    for(int e = first[u]; e; e = nxt[e]) {
        int v = to[e];
        tag[v] += tag[u];
        dfs(v);
    }
}
signed main() {
    int n = Read(), m = Read(), q = Read();
    for(int i = 1; i <= n; i++)  sz[i] = bh[i] = 1, rt[i] = i, a[i] = Read();
    for(int i = 1; i <= m; i++)  ex[i] = Read(), ey[i] = Read();
    for(int i = 1; i <= q; i++) {
        opt[i] = Read(), x[i] = Read();
        if(opt[i] == 2)  vis[x[i]] = 1;
    }
    for(int i = 1; i <= m; i++) {
        if(!vis[i]) {
            int fx = findfa(ex[i]), fy = findfa(ey[i]);
            if(fx == fy)  continue;
            tag[fx] += sz[fy];
            sz[fy] += sz[fx]; rt[fx] = fy;
            Add(fy, fx);
        }
    }
    for(int i = q; i >= 1; i--) {
        if(opt[i] == 2) {
            int fx = findfa(ex[x[i]]), fy = findfa(ey[x[i]]);
            if(fx == fy)  continue;
            tag[fx] += sz[fy];
            sz[fy] += sz[fx]; rt[fx] = fy;
            Add(fy, fx);
        }
    }
    int sum = 0;
    for(int i = 1; i <= n; i++)
        if(!vvis[findfa(i)])  tag[rt[i]] += sum, sum += sz[rt[i]], dfs(rt[i]);
    for(int i = 1; i <= n; i++)
        maxn[i] = minn[i] = bh[i], rt[i] = i, rev[bh[i]] = i;
    for(int i = 1; i <= m; i++) {
        if(!vis[i]) {
            int fx = findfa(ex[i]), fy = findfa(ey[i]);
            if(fx == fy)  continue;
            maxn[fy] = max(maxn[fy], maxn[fx]);
            minn[fy] = min(minn[fy], minn[fx]);
            rt[fx] = fy;
        }
    }
    for(int i = q; i >= 1; i--) {
        if(opt[i] == 2) {
            int fx = findfa(ex[x[i]]), fy = findfa(ey[x[i]]);
            if(fx == fy)  continue;
            maxn[fy] = max(maxn[fy], maxn[fx]);
            minn[fy] = min(minn[fy], minn[fx]);
            rt[fx] = fy;
        }
        if(opt[i] == 1)
            L[i] = minn[findfa(x[i])], R[i] = maxn[findfa(x[i])];
    }
    build(1, 1, n);
    for(int i = 1; i <= q; i++) {
        if(opt[i] == 1) {
            pair<int, int> tmp = query(1, 1, n, L[i], R[i]);
            printf("%d\n", tmp.first);
            modify(1, 1, n, tmp.second, 0);
        }
    }
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define M 500005
typedef pair<vector<int>, int> pvi;

int pp[M];
int uu[M], vv[M];
int tp[M], id[M];
bool ase[M];
int boss[M];
vector<int> vec[M];
pvi cng[M];

void mf(int a, int b)
{
    int u = boss[a], v = boss[b];
    if(u == v) return;

    if(vec[u].size() > vec[v].size()) swap(u, v);

    for(int x: vec[u])
    {
        boss[x] = v;
        vec[v].push_back(x);
    }
}

bool cmp(int a, int b) { return pp[a] < pp[b]; }

int main()
{
    int n, m, q;
    scanf("%d %d %d", &n, &m, &q);

    for(int i = 1; i <= n; i++) scanf("%d", pp+i);
    for(int i = 1; i <= m; i++) scanf("%d %d", uu+i, vv+i);
    for(int i = 1; i <= q; i++) scanf("%d %d", tp+i, id+i);

    for(int i = 1; i <= q; i++)
    {
        if(tp[i] == 2) ase[id[i]] = true;
    }

    for(int i = 1; i <= n; i++) boss[i] = i, vec[i].push_back(i);
    for(int i = 1; i <= m; i++)
    {
        if(!ase[i]) mf(uu[i], vv[i]);
    }

    for(int i = q; i; i--)
    {
        if(tp[i] == 1) continue;
        int u = boss[uu[id[i]]], v = boss[vv[id[i]]];
        if(u == v) continue;
        if(vec[u].size() > vec[v].size()) swap(u, v);

        cng[i] = {vec[u], u};
        mf(uu[id[i]], vv[id[i]]);
    }

    for(int i = 1; i <= n; i++) sort(vec[i].begin(), vec[i].end(), cmp);

    for(int i = 1; i <= q; i++)
    {
        if(tp[i] == 1)
        {
            int u = boss[id[i]];
            while(vec[u].size() && (boss[vec[u].back()] != u || !pp[vec[u].back()])) vec[u].pop_back();

            int ans = 0;
            if(vec[u].size()) ans = pp[vec[u].back()], pp[vec[u].back()] = 0;

            printf("%d\n", ans);
        }
        else
        {
            for(int x: cng[i].first) boss[x] = cng[i].second;
        }
    }

    return 0;
}

#include <cstdio>
#include <vector>
#include <algorithm>
#include <iostream>
#include <set>

using namespace std;

#define f first
#define s second

const int MAXN = 5e5 + 3;

int w[MAXN];
bool us[MAXN];
bool was[MAXN];
bool nal[MAXN];
int repr[MAXN];
int nas[MAXN];
int lst[MAXN];
int roz[MAXN];
int who[MAXN];
multiset<int> q[MAXN];
pair<int, int> pol[MAXN];
pair<int, int> zap[MAXN];

int fnd(int x) {
    if (repr[x] == x)
        return x;
    return repr[x] = fnd(repr[x]);
}

void onion(int x, int y, int ind, int ind2) {
    x = fnd(x);
    y = fnd(y);
    if (x == y)
        return;
    if (roz[x] < roz[y]) {
        swap(pol[ind].f, pol[ind].s);
        swap(x, y);
    }
    nal[ind2] = true;
    who[ind2] = y;
    repr[y] = x;
    nas[lst[x]] = y;
    lst[x] = lst[y];
    roz[x] += roz[y];
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m, z;
    int x, y, war, pocz, sec;
    cin >> n >> m >> z;
    for (int i = 1; i <= n; i++) {
        cin >> w[i];
        w[i] *= -1;
    }
    for (int i = 1; i <= m; i++)
        cin >> pol[i].f >> pol[i].s;
    for (int i = 1; i <= z; i++) {
        cin >> zap[i].f >> zap[i].s;
        if (zap[i].f == 2)
            us[zap[i].s] = true;
    }
    for (int i = 1; i <= n; i++) {
        repr[i] = nas[i] = lst[i] = i;
        roz[i] = 1;
    }
    for (int i = 1; i <= m; i++) {
        if (!us[i])
            onion(pol[i].f, pol[i].s, i, 0);
    }
    for (int i = z; i > 0; i--) {
        if (zap[i].f == 2)
            onion(pol[zap[i].s].f, pol[zap[i].s].s, zap[i].s, i);
    }
    for (int i = 1; i <= n; i++)
        q[fnd(i)].insert(w[i]);

    for (int i = 1; i <= z; i++) {
        if (zap[i].f == 1) {

            x = fnd(zap[i].s);
            war = -(*q[x].begin());
            cout << war << '\n';
            q[x].erase(q[x].begin());
            q[x].insert(0);

            was[war] = true;
        }
        else if (nal[i]) {

            x = pol[zap[i].s].f;
            x = fnd(x);
            pocz = y = who[i];
            sec = lst[y];

            while (true) {
                repr[y] = pocz;
                if (!was[-w[y]]) {
                    q[pocz].insert(w[y]);
                    q[x].erase(q[x].find(w[y]));
                }
                else
                    q[pocz].insert(0);
                if (y == sec)
                    break;
                y = nas[y];
            }

            continue;
        }
    }
    return 0;
}

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=1e6+100;

int n,m,q;

struct Qu
{
	int op,x;
}qu[N];

struct Edge
{
	int u,v,w;
	bool operator<(const Edge& t)const
	{
		return w<t.w;
	}
}edge[N];

struct Max
{
	int val,pos;
	Max(){}
	Max(int val,int pos):val(val),pos(pos){}
	static Max inf()
	{
		return Max(-0x3f3f3f3f,0);
	}
	bool operator<(const Max& t)const
	{
		return val<t.val;
	}
};

struct Node
{
	int l,r;
	Max mmax;
}tree[N<<2];

int a[N],f[N],val[N],dp[N][25],L[N],R[N],id[N],tot;

vector<int>node[N];
/*线段树*/
void pushup(int k)
{
	tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax);
}

void build(int k,int l,int r)
{
	tree[k].l=l;
	tree[k].r=r;
	if(l==r)
	{
		tree[k].mmax.val=a[id[l]];
		tree[k].mmax.pos=l;
		return;
	}
	int mid=l+r>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	pushup(k);
}

void update(int k,int pos)
{
	if(tree[k].l==tree[k].r)
	{
		tree[k].mmax.val=0;
		return;
	}
	int mid=tree[k].l+tree[k].r>>1;
	if(pos<=mid)
		update(k<<1,pos);
	else
		update(k<<1|1,pos);
	pushup(k);
}

Max query(int k,int l,int r)
{
	if(tree[k].l>r||tree[k].r<l)
		return Max::inf();
	if(tree[k].l>=l&&tree[k].r<=r)
		return tree[k].mmax;
	return max(query(k<<1,l,r),query(k<<1|1,l,r));
}
/*线段树*/
/*dfs序+树上倍增*/
void dfs(int u,int fa)
{
	dp[u][0]=fa;
	for(int i=1;i<=20;i++)
		dp[u][i]=dp[dp[u][i-1]][i-1];
	L[u]=++tot;
	id[tot]=u;
	for(auto v:node[u])
		dfs(v,u);
	R[u]=tot;
}

int get_pos(int u,int up)//树上倍增找满足的祖先
{
	for(int i=20;i>=0;i--)
		if(dp[u][i]!=0&&val[dp[u][i]]<=up)
			u=dp[u][i];
	return u;
}
/*dfs序+树上倍增*/
/*并查集+克鲁斯卡尔重构树*/
int find(int x)
{
	return f[x]==x?x:f[x]=find(f[x]);
}

int Ex_Kruskal()
{
	for(int i=1;i<=n<<1;i++)
		f[i]=i;
	int index=n;
	sort(edge+1,edge+1+m);
	for(int i=1;i<=m;i++)
	{
		int xx=find(edge[i].u),yy=find(edge[i].v);
		if(xx!=yy)
		{
			f[xx]=f[yy]=++index;
			val[index]=edge[i].w;
			node[index].push_back(xx);
			node[index].push_back(yy);
		}
	}
	int last=1;
	for(int i=1;i<=n;i++)
	{
		int xx=find(last),yy=find(i);
		if(xx!=yy)
		{
			f[xx]=f[yy]=++index;
			val[index]=inf;
			node[index].push_back(xx);
			node[index].push_back(yy);
			last=index;
		}
	}
	return index;
}
/*并查集+克鲁斯卡尔重构树*/
int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)
		scanf("%d",a+i);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&edge[i].u,&edge[i].v);
		edge[i].w=0;
	}
	int val=inf;
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&qu[i].op,&qu[i].x);
		if(qu[i].op==2)
			edge[qu[i].x].w=--val;
	}
	int root=Ex_Kruskal();
	dfs(root,0);
	build(1,1,root);
	val=inf-1;
	for(int i=1;i<=q;i++)
	{
		if(qu[i].op==1)
		{
			int x=get_pos(qu[i].x,val);
			Max ans=query(1,L[x],R[x]);
			printf("%d\n",ans.val);
			update(1,ans.pos);
		}
		else
			val--;
	}

    return 0;
}

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pi;
typedef pair<ll,ll> pl;
#define F first
#define S second
#define endl '\n'
#define all(x) (x).begin(),(x).end()
#ifdef dremix
    #define p(x) cerr<<#x<<" = "<<x<<endl;
    #define p2(x,y) cerr<<#x<<" , "<<#y<<" = "<<x<<" , "<<y<<endl;
    #define pp(x) cerr<<#x<<" = ("<<x.F<<" , "<<x.S<<")"<<endl;
    #define pv(x) cerr<<#x<<" = {";for(auto u : x)cerr<<u<<", ";cerr<<"}"<<endl;
    #define ppv(x) cerr<<#x<<" = {";for(auto u : x)cerr<<u.F<<"-"<<u.S<<", ";cerr<<"}"<<endl;
#else
    #define p(x)
    #define p2(x,y)
    #define pp(x)
    #define pv(x)
    #define ppv(x)
#endif
#define fastio ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int maxp = 22;
const ld EPS = 1e-18;
const ll INF = 1e18;
const int MOD = 1e9+7;
const int N = 4e5+1;

vector<vector<int> > nodes(N);
vector<int> par(N,0);

int find(int x){
    return (par[x]==x) ? x : par[x] = find(par[x]);
}

void join(int x, int y, vector<int> &v){
    x = find(x);
    y = find(y);
    if(x==y)return;
    if(nodes[x].size() < nodes[y].size())
        swap(x,y);

    v = nodes[y];
    for(int g : nodes[y])
        nodes[x].push_back(g);

    par[y] = x;
    nodes[y].clear();
}

int main(){
fastio

int n,m,q;
cin>>n>>m>>q;

int arr[n+1],i,inv[n+1];

for(i=1;i<=n;i++){
    cin>>arr[i];
    inv[arr[i]] = i;
    nodes[i].push_back(i);
}
pi edges[m+1];

for(i=1;i<=m;i++)
    cin>>edges[i].F>>edges[i].S;

pi ask[q];
bool rem[m+1] = {};

for(i=0;i<q;i++){
    cin>>ask[i].F>>ask[i].S;
    if(ask[i].F==2){
        rem[ask[i].S] = true;
    }
}

iota(all(par),0);

for(i=1;i<=m;i++){
    if(rem[i])continue;
    vector<int> fake;
    join(edges[i].F,edges[i].S,fake);
}

vector<vector<int> > save(q);

for(i=q-1;i>=0;i--){
    if(ask[i].F == 1)continue;
    int idx = ask[i].S;
    join(edges[idx].F,edges[idx].S,save[i]);
    p(i)
    pv(save[i])
}

vector<set<int> > s(N*2);

for(i=1;i<=n;i++){

    if(find(i)==i){
        p(i)
        pv(nodes[i])
        assert(!nodes[i].empty());
        for(auto x : nodes[i]){
            s[i].insert(arr[x]);
        }
        pv(s[i])
    }
}

int curr = n+1;

for(i=0;i<q;i++){
    if(ask[i].F == 1){
        int x = ask[i].S;
        x = find(x);
        p(x)
        pv(s[x])
        if(!s[x].empty()){
            auto it = s[x].end();
            it--;
            cout<<*it<<endl;
            arr[inv[*it]] = 0;
            s[x].erase(it);
        }
        else
            cout<<0<<endl;
    }
    else{
        if(save[i].empty())continue;
        int x = find(save[i][0]);
        pv(save[i])
        for(auto v : save[i]){
            s[x].erase(arr[v]);
            s[curr].insert(arr[v]);
            par[v] = curr;
        }
        curr++;
    }
}

}

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int N=200005;
struct DSU
{
    vector<int> p;
    vector<int> sz;
    DSU(int n)
    {
        p.assign(n+1,0);
        for(int i=0;i<=n;i++) p[i]=i;
        sz.assign(n+1,1);
    }
    int find_set(int a)
    {
        if(a==p[a]) return a;
        else return p[a]=find_set(p[a]);
    }
    int merge_sets(int a,int b) //returns component with smaller size, or -1 if they are already connected
    {
        int origa=a;
        int origb=b;
        a=find_set(a);
        b=find_set(b);
        if(a==b) return -1;
        if(sz[a]<sz[b])
        {
            swap(a,b);
            swap(origa,origb);
        }
        p[b]=a;
        sz[a]+=sz[b];
        return origb;
    }
};

vector<set<int>> v(N);
vector<int> val(N,0);
vector<int> leader(N,0);
vector<set<int>> s(2*N);
int lidx=1;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n,m,q;
    cin >> n >> m >> q;
    vector<array<int,2>> edges(m+1,{0,0});
    DSU dsu(n);
    for(int i=1;i<=n;i++) cin >> val[i];
    for(int i=1;i<=m;i++)
    {
        int a,b;
        cin >> a >> b;
        edges[i]={a,b};
        v[a].insert(b);
        v[b].insert(a);
    }
    vector<bool> removed_edges(m+1,0);
    vector<array<int,2>> queries(q+1,{0,0});
    for(int i=1;i<=q;i++)
    {
        int t,a;
        cin >> t >> a;
        queries[i]={t,a};
        if(t==2) removed_edges[a]=1;
    }
    vector<int> disconnects(q+1,0); //0 if nothing is disconnected, the vertex with smaller current size otherwise
    for(int i=1;i<=m;i++) if(removed_edges[i]==0) dsu.merge_sets(edges[i][0],edges[i][1]);
    for(int i=q;i>=1;i--)
    {
        auto [t,a]=queries[i];
        if(t==1) continue;
        int x=dsu.merge_sets(edges[a][0],edges[a][1]);
        if(x!=-1) disconnects[i]=x;
    }
    for(int i=1;i<=n;i++)
    {
        if(leader[i]!=0) continue;
        queue<int> z;
        z.push(i);
        int now=lidx++;
        leader[i]=now;
        s[now].insert(val[i]);
        while(!z.empty())
        {
            int a=z.front();
            z.pop();
            for(int to:v[a])
            {
                if(leader[to]!=0) continue;
                leader[to]=now;
                s[now].insert(val[to]);
                z.push(to);
            }
        }
    }
    vector<bool> used(n+1,0);
    vector<int> h(n+1,0);
    for(int i=1;i<=n;i++) h[val[i]]=i;
    //set val[a]=0;
    for(int i=1;i<=q;i++)
    {
        auto [t,a]=queries[i];
        if(t==1)
        {
            int res=0;
            if(!s[leader[a]].empty())
            {
                int mx=(*s[leader[a]].rbegin());
                s[leader[a]].erase(mx);
                val[h[mx]]=0;
                res=mx;
            }
            cout << res << "\n";
        }
        else if(t==2)
        {
            auto [x,y]=edges[a];
            v[x].erase(y);
            v[y].erase(x);
            int src=disconnects[i];
            if(src!=0)
            {
                queue<int> z;
                z.push(src);
                int prv=leader[src];
                int now=lidx++;
                leader[src]=now;
                if(val[src]!=0) s[prv].erase(val[src]);
                if(val[src]!=0) s[now].insert(val[src]);
                while(!z.empty())
                {
                    int e=z.front();
                    z.pop();
                    for(int to:v[e])
                    {
                        if(leader[to]==now) continue;
                        leader[to]=now;
                        z.push(to);
                        if(val[to]!=0) s[prv].erase(val[to]);
                        if(val[to]!=0) s[now].insert(val[to]);
                    }
                }
            }
        }
    }
    return 0;
}

#include <stdio.h>
#include <bits/stdc++.h>

using namespace std;

const int N = 200005;
const int M = 300005;
const int Q = 500005;

int n, m, q, ori;
int ea[M], eb[M], er[M];
int type[Q], qu[Q];
int c[N+N];
int dup[N+N][20];
int par[N+N];

vector<int> g[N+N];
int in[N+N], out[N+N], dfs_t;

void dfs(int u) {
	if(u <= ori) {
		in[u] = ++dfs_t;
		out[u] = dfs_t;
		return;
	}
	in[u] = -1;
	for(int v : g[u]) {
		dfs(v);
		if(in[u] == -1) in[u] = in[v];
	}
	out[u] = dfs_t;
}

int f(int u) {
	return u == par[u] ? u : par[u] = f(par[u]);
}

int get_root(int u, int ti) {

	for(int j = 19; j >= 0; j--) {
		if(c[ dup[u][j] ] > ti) {
			u = dup[u][j];
		}
	}
	return u;
}

int st[2*N];

void upd(int x, int val) {
	x--;
	st[x += ori] = val;
	while(x >>= 1) st[x] = max(st[2 * x], st[2 * x + 1]);
}
int query(int l, int r) {
	l--, r--;
	int ans = 0;
	for(l += ori, r += ori + 1; l < r; l >>= 1, r >>= 1) {
		if(l & 1) ans = max(ans, st[l++]);
		if(r & 1) ans = max(ans, st[--r]);
	}
	return ans;
}

int p[N], rp[N];

int main() {
	scanf("%d %d %d", &n, &m, &q);
	ori = n;

	for(int i = 1; i <= n; i++) scanf("%d", p + i);

	for(int i = 1; i <= m; i++) {
		scanf("%d %d", ea + i, eb + i);
	}

	for(int i = 0; i < q; i++) {
		scanf("%d %d", type + i, qu + i);
		if(type[i] == 2) er[ qu[i] ] = 1;
	}

	for(int i = 1; i <= n; i++) par[i] = i, c[i] = q;

	for(int i = 1; i <= m; i++) if(!er[i]) {
		int a = f(ea[i]), b = f(eb[i]);
		if(a == b) continue;
		++n;
		dup[a][0] = dup[b][0] = n;
		par[a] = par[b] = par[n] = n;
		c[n] = q;
		g[n].push_back(a);
		g[n].push_back(b);
	}

	for(int i = q - 1; i >= 0; i--) if(type[i] == 2) {
		int a = f(ea[ qu[i] ]), b = f(eb[ qu[i] ]);
		if(a == b) continue;
		++n;
		dup[a][0] = dup[b][0] = n;
		par[a] = par[b] = par[n] = n;
		c[n] = i;
		g[n].push_back(a);
		g[n].push_back(b);
	}

	for(int i = 2; i <= ori; i++) if(f(i) != f(1)) {
		int a = f(1), b = f(i);
		++n;
		dup[a][0] = dup[b][0] = n;
		par[a] = par[b] = par[n] = n;
		c[n] = -1;
		g[n].push_back(a);
		g[n].push_back(b);
	}

	dup[n][0] = n;

	for(int lvl = 0; lvl + 1 < 20; lvl++) {
		for(int i = 1; i <= n; i++) {
			dup[i][lvl + 1] = dup[ dup[i][lvl] ][lvl];
		}
	}

	dfs(n);

	for(int i = 1; i <= ori; i++) {
		upd(in[i], p[i]);
		rp[ p[i] ] = in[i];
	}

	for(int i = 0; i < q; i++) {
		if(type[i] == 1) {
			int r = get_root(qu[i], i);
			int val = query(in[r], out[r]);
			printf("%d\n", val);
			if(val) upd(rp[val], 0);
		}
	}
}

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Query{
	int opt,x,rx,ry;
}q[500005];
int n,m,Q,fa[200005],ex[300005],ey[300005],del[300005],sz[300005],bel[200005],a[200005],used[200005];
vector<int> h[200005];
int gf(int x){
	return fa[x]==x?x:gf(fa[x]);
}
inline int Query(int x)
{
	while(h[x].size()&&(bel[h[x].back()]!=x||used[h[x].back()])) h[x].pop_back();
	if(!h[x].size()) return 0;
	int ans=h[x].back();
	h[x].pop_back(),used[ans]=1;
	return ans;
}
int main() {
	scanf("%d%d%d",&n,&m,&Q);
	for(int i=1,x;i<=n;i++)scanf("%d",&x),h[fa[i]=i].push_back(a[i]=x),sz[i]=1;
	for(int i=1;i<=m;i++)scanf("%d%d",&ex[i],&ey[i]);
	for(int i=1;i<=Q;i++){
		scanf("%d%d",&q[i].opt,&q[i].x);
		if(q[i].opt==2)del[q[i].x]=1;
	}
	for ( int i=1;i<=m;i++ ) if(!del[i])
	{
		int fx=gf(ex[i]),fy=gf(ey[i]);
		if(fx==fy) continue;
		if(sz[fx]>sz[fy]) swap(fx,fy);
		for ( int j=0;j<h[fx].size();j++ ) h[fy].push_back(h[fx][j]);
		fa[fx]=fy,sz[fy]+=sz[fx];
	}
	for ( int i=Q;i>=1;i-- )
	{
		int op=q[i].opt,x=q[i].x;
		int fx=gf(ex[x]),fy=gf(ey[x]);
		if(fx==fy||op==1) continue;
		if(sz[fx]>sz[fy]) swap(fx,fy);
		fa[fx]=fy,sz[fy]+=sz[fx],q[i].rx=fx;
		for ( int j=0;j<h[fx].size();j++ ) h[fy].push_back(h[fx][j]);
	}
	for(int i=1;i<=n;i++)sort(h[i].begin(),h[i].end()),bel[a[i]]=gf(i);
	for(int i=1,u;i<=Q;i++){
		if(q[i].opt==1)printf("%d\n",u=Query(gf(q[i].x)));
		else if(q[i].rx){
			for ( int j=0;j<h[q[i].rx].size();j++ ) bel[h[q[i].rx][j]]=q[i].rx;
			for(int j:h[q[i].rx])bel[j]=q[i].rx;
			fa[q[i].rx]=q[i].rx;
		}
	}
	return 0;
}

#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,fma")
#pragma GCC optimize("unroll-loops")

#pragma GCC optimize("O3")
#pragma GCC optimize("O2")
#pragma GCC optimize("Og")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
// #include <bits/stdc++.h>
#include <complex>
#include <queue>
#include <set>
#include <unordered_set>
#include <list>
#include <chrono>
#include <random>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <map>
#include <unordered_map>
#include <stack>
#include <iomanip>
#include <fstream>
#include <functional> // for less
#include <iostream>
using namespace std;

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<int, int> p32;
typedef pair<ll, ll> p64;
typedef pair<double, double> pdd;
typedef vector<ll> v64;
typedef vector<int> v32;
typedef vector<vector<int>> vv32;
typedef vector<vector<ll>> vv64;
#define vvv64 vector<vv64>
#define vvvv64 vector<vvv64>

typedef vector<vector<p64>> vvp64;
typedef vector<p64> vp64;
typedef vector<p32> vp32;
ll MOD = 998245709;
#define forn(i, e) for (ll i = 0; i < e; i++)
#define forsn(i, s, e) for (ll i = s; i < e; i++)
#define rforn(i, s) for (ll i = s; i >= 0; i--)
#define rforsn(i, s, e) for (ll i = s; i >= e; i--)
#define ln "\n"
#define dbg(x) cout << #x << " = " << x << ln
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define INF 1e18
#define fast_cin()                    \
    ios_base::sync_with_stdio(false); \
    cin.tie(NULL);                    \
    cout.tie(NULL)
#define all(x) (x).begin(), (x).end()
#define sz(x) ((ll)(x).size())
#define vc vector<char>
#define vvc vector<vc>
#define pp pair<p64, ll>
ll exp(ll n, ll e)
{
    if (e == 0)
        return 1;
    ll temp = exp((n * n) % MOD, e / 2);
    return e % 2 == 0 ? temp : (temp * n) % MOD;
}
ll inverse(ll n)
{
    return exp(n, MOD - 2);
}
void frac(ll p, ll q)
{
    cout << (p * inverse(q)) % MOD << endl;
}

ll ceil_div(ll a, ll b)
{
    return (a + b - 1) / b;
}

const int LIM = 2e5 + 5;
const int LIM2 = 5e5 + 5;
int value[LIM];
int par1[LIM2], par2[LIM2];
// set<p32> rem2[LIM2];
vector<v32> rem3(LIM2);
class UnionFind
{
public:
    v32 p, sz;
    vector<set<p32>> elements;
    void init(int N)
    {
        elements = vector<set<p32>>(N);
        p.assign(N, 0);
        sz.assign(N, 1);
        forn(i, N)
        {
            p[i] = i;
            elements[i].insert({value[i], i});
        }
    }
    int findSet(ll i)
    { // returns the head of group containing element i
        return (p[i] == i) ? i : findSet(p[i]);
    }
    void answer(int x)
    {
        int a = findSet(x);
        auto it = *elements[a].rbegin();
        cout << it.first << '\n';
        elements[a].erase(it);
        elements[a].insert({0, it.se});
        value[it.se] = 0;
    }
    void unionSet(int i, int j, int k)
    { // unify group containing i and j(if already in same set then do nothing)
        int x = findSet(i), y = findSet(j);
        if (x != y)
        {
            if (sz[x] > sz[y])
                swap(x, y);
            if (k >= 0)
            {
                par1[k] = x;
                par2[k] = y;
            }
            p[x] = y;
            sz[y] += sz[x];
            for (auto &it : elements[x])
            {
                elements[y].insert(it);
                if (k >= 0)
                {
                    // rem2[k].insert(it);
                    rem3[k].push_back(it.se);
                }
            }
            elements[x].clear();
        }
    }
    int sz1(int i)
    {
        return sz[i];
    }
};
int query1[LIM2], query2[LIM2];
const int LIM3 = 3e5 + 5;
bool remov[LIM3];
int u[LIM3], v[LIM3];
UnionFind dsu;
void solve()
{
    //Read Comments below main
    int n, m, q;
    cin >> n >> m >> q;
    for (int i = 1; i <= n; i++)
        cin >> value[i];
    // UnionFind dsu(n + 1);
    dsu.init(n + 1);
    for (int i = 1; i <= m; i++)
    {
        int a, b;
        cin >> u[i] >> v[i];
    }
    for (int i = 0; i < q; i++)
    {
        int op, x;
        cin >> op >> x;
        if (op == 2)
            remov[x] = 1;
        query1[i] = op;
        query2[i] = x;
    }
    for (int i = 1; i <= m; i++)
    {
        if (remov[i] == 0)
        {
            dsu.unionSet(u[i], v[i], -1);
        }
    }
    for (int i = q - 1; i >= 0; i--)
    {
        int op = query1[i];
        int x = query2[i];
        if (op == 2)
        {
            dsu.unionSet(u[x], v[x], i);
        }
    }
    for (int i = 0; i < q; i++)
    {
        if (query1[i] == 1)
        {
            dsu.answer(query2[i]);
        }
        else
        {
            int p1 = par1[i];
            int p2 = par2[i];
            dsu.p[p1] = p1;
            // for (auto &it : rem2[i])
            for (auto &it : rem3[i])
            {
                dsu.elements[p2].erase({value[it], it});
                dsu.elements[p1].insert({value[it], it});
            }
            // rem2[i].clear();
            rem3[i].clear();
        }
    }
}

int32_t main()
{
    fast_cin();
    ll t = 1;
    // cin >> t;
    for (ll i = 1; i <= t; i++)
    {
        solve();
    }
    return 0;
}
// BITMASK:
// 1)When some constrall is of the order of 15-20, think of bitmask DP.
// 2)When some constrall is around 40, try out meet in the middle
// 3) See Strings,palindromes,prefix,suffix etc -> KMP,Z algorithm

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=600010,M=300010,Q=500010;
struct edge1{
	int u,v,flag;
}d1[M];
struct edge{
	int y,next;
}data[N];
struct qry{
	int x,tp;
}q1[Q];
int n,m,q,num,num1,num2,p1[N],dfn[N],tid[N],lst[N],fa[N],h[N],pos[N],tree[N*4];
inline int read(){
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x;
}
int getfa1(int x){
	if(fa[x]!=x)fa[x]=getfa1(fa[x]);
	return fa[x];
}
inline void addedge(int u,int v){
	data[++num].y=v,data[num].next=h[u],h[u]=num;
}
void dfs(int u){
	dfn[u]=++num2;tid[num2]=u;
	for(int i=h[u],v;i!=-1;i=data[i].next){
		v=data[i].y;dfs(v);
	}
	lst[u]=num2;
}
void print(int p,int pa,int pb){
	printf("%d:%d-%d mx%d pos%d\n",p,pa,pb,tree[p],tree[p]);
	if(pa==pb)return;
	int mid=(pa+pb)>>1;
	print(p<<1,pa,mid);print(p<<1|1,mid+1,pb);
}
inline max1(int i,int j){return i>j?i:j;}
inline void update(int p){tree[p]=max1(tree[p<<1],tree[p<<1|1]);}
void build(int p,int pa,int pb){
	if(pa==pb){tree[p]=p1[tid[pa]];pos[p1[tid[pa]]]=p;return;}
	int mid=(pa+pb)>>1;
	build(p<<1,pa,mid);build(p<<1|1,mid+1,pb);
	update(p);
}
int query(int p,int pa,int pb,int a,int b){
	if(a<=pa&&pb<=b)return tree[p];
	int mid=(pa+pb)>>1,q1=0,q2=0;
	if(a<=mid)q1=query(p<<1,pa,mid,a,b);
	if(mid<b)q2=query(p<<1|1,mid+1,pb,a,b);
	return max1(q1,q2);
}
int main(){
//	freopen("cf1417f.in","r",stdin);
//	freopen("cf1417f.out","w",stdout);
	n=read(),m=read(),q=read();
	for(int i=1;i<=n;++i)p1[i]=read(),fa[i]=i;
	for(int i=1;i<=m;++i)d1[i].u=read(),d1[i].v=read(),d1[i].flag=1;
	for(int i=1;i<=q;++i){
		q1[i].tp=read(),q1[i].x=read();
		if(q1[i].tp==2)d1[q1[i].x].flag=0;
	}
	num=0;memset(h,-1,sizeof h);
	for(int i=1,uu,vv;i<=m;++i)
		if(d1[i].flag){
			uu=getfa1(d1[i].u),vv=getfa1(d1[i].v);
			fa[uu]=vv;
		}
	for(int i=1,x;i<=n;++i){
		x=getfa1(i);if(x!=i)addedge(x,i);
	}
	num1=n;
	for(int i=q,uu,vv;i>=1;--i){
		if(q1[i].tp==1){
			q1[i].x=getfa1(q1[i].x);
			//printf("%d %d\n",i,q1[i].x);
		}else{
			uu=getfa1(d1[q1[i].x].u),vv=getfa1(d1[q1[i].x].v);
			if(uu==vv)continue;
			p1[++num1]=0;
			fa[uu]=fa[vv]=fa[num1]=num1;
			addedge(num1,uu),addedge(num1,vv);
		}
	}
	p1[num1+1]=0;
	for(int i=1;i<=num1;++i)if(getfa1(i)==i)addedge(num1+1,i);
//	for(int i=1;i<=num1+1;++i){
//		printf("%d:",i);
//		for(int j=h[i];j!=-1;j=data[j].next)printf("%d ",data[j].y);
//		printf("\n");
//	}
	num2=0;dfs(num1+1);
//	for(int i=1;i<=num1+1;++i)printf("%d %d %d\n",i,dfn[i],lst[i]);
	build(1,1,num2);tree[0]=-1;
//	print(1,1,num2);printf("\n");
	for(int i=1,x,y;i<=q;++i){
		if(q1[i].tp==2)continue;
		y=query(1,1,num2,dfn[q1[i].x],lst[q1[i].x]);
		printf("%d\n",y);
		if(y!=0){
			x=pos[y];tree[x]=0;x>>=1;
			while(x){update(x);x>>=1;}
		}
//		print(1,1,num2);printf("\n");
	}
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
const int mod=1e9+7;
#define pb push_back
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=n;i>=a;i--)
typedef long long ll;
typedef double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
ll qpow(ll a,ll b){ll ans=1;a%=mod;assert(b>=0);for(;b;b>>=1){if(b&1)ans=ans*a%mod;a=a*a%mod;}return ans;}
ll gcd(ll a,ll b){return b>0?gcd(b,a%b):a;}
int n,m,T,N;
int pre[maxn],a[maxn],p[maxn];
int Find(int x){
	return pre[x]==x?x:pre[x]=Find(pre[x]);
}
struct QUERY{
	int o,x,t;
}q[maxn];

struct Edge{
	int u,v;
}e[maxn];

int flag[maxn];
int rmq[maxn][35];
vi g[maxn];
int L[maxn],R[maxn],d[maxn],tot;
bool bk[maxn];
void dfs(int u){
	flag[u]=1;
	if(d[u]){
		a[++tot]=d[u];
		L[u]=tot;
	}
	else L[u]=tot+1;
	for(auto v:g[u]){
		dfs(v);
	}
	R[u]=tot;
}
void init(){
	for(int i=1;i<=n;i++) pre[i]=i,d[i]=i,rmq[i][0]=i;
	for(int i=1;i<=m;i++){
		if(flag[i])continue;
		int fax=Find(e[i].u);
		int fay=Find(e[i].v);
		if(fax==fay) continue;
		rmq[fax][0]=fay;
		pre[fax]=fay;
		g[fay].pb(fax);
	}
	N=n;
	for(int i=T;i>=1;i--){
		if(q[i].o==1)continue;
		int fax=Find(e[q[i].x].u);
		int fay=Find(e[q[i].x].v);
		if(fax==fay)continue;
		++N;
		pre[N]=N;
		rmq[N][0]=N;
		bk[i]=1;
		rmq[fax][0]=N;
		rmq[fay][0]=N;
		pre[fax]=N;
		pre[fay]=N;
		g[N].pb(fax);
		g[N].pb(fay);
	}
	for(int bit=1;bit<=30;bit++){
		for(int i=1;i<=N;i++){
			rmq[i][bit]=rmq[rmq[i][bit-1]][bit-1];
		}
	}
	memset(flag,0,sizeof flag);
	tot=0;
	for(int i=N;i>=1;i--){
		if(flag[i])continue;
		dfs(i);
	}
}
pii tr[maxn<<2];
#define lson rt<<1
#define rson rt<<1|1
void build(int l,int r,int rt){
	 if(l==r){
	 	tr[rt]={p[a[l]],l};
	 	return;
	 }
	 int mid=l+r>>1;
	 build(l,mid,lson);
	 build(mid+1,r,rson);
	 tr[rt]=max(tr[lson],tr[rson]);
}
void update(ll C,int pos,int l,int r,int rt){
	if(pos<l||pos>r) return;
	if(l==r){
		tr[rt]={C,l};
		return;
	}
	int mid=l+r>>1;
	update(C,pos,l,mid,lson);
	update(C,pos,mid+1,r,rson);
	tr[rt]=max(tr[lson],tr[rson]);
}
pii query(int L,int R,int l,int r,int rt){
	if(r<L||R<l) return {0,0};
	if(L<=l&&r<=R){
		return tr[rt];
	}
	int mid=l+r>>1;
	return max(query(L,R,l,mid,lson),query(L,R,mid+1,r,rson));
}
int main() {
	cin>>n>>m>>T;
	for(int i=1;i<=n;i++) cin>>p[i];
	for(int i=1;i<=m;i++){
		scanf("%d%d",&e[i].u,&e[i].v);
	}
	for(int i=1;i<=T;i++){
		scanf("%d%d",&q[i].o,&q[i].x);
		q[i].t=i;
		if(q[i].o==2) flag[q[i].x]=1;
	}
	init();
	memset(flag,0,sizeof flag);
	build(1,N,1);
	for(int i=1;i<=T;i++){
		if(q[i].o==1){
			int now=q[i].x;
			for(int bit=30;bit>=0;bit--){
				int to=rmq[now][bit];
				if(flag[to])continue;
				now=to;
			}
			pii res=query(L[now],R[now],1,N,1);
			cout<<res.fi<<"\n";
			update(0,res.se,1,N,1);
		}else if(bk[i]){
			int now=e[q[i].x].u;
			for(int bit=30;bit>=0;bit--){
				int to=rmq[now][bit];
				if(flag[to])continue;
				now=to;
			}
			flag[now]=1;
		}
	}
	return 0;
}
/*
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
*/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include <vector>

#define rep(i,l,r) for (i=l;i<=r;i++)
#define drep(i,l,r) for (i=l;i>=r;i--)
using namespace std;

const int N = 210000, M = 310000, Q = 510000;

int i,j,k,l,m,n,q,o,tot,p[N],a[M],b[M],is_alive[M],cmd[Q],key[Q];
int belong[N],visit[N], e[M*2], sta[N], nex[M*2], lastq;

inline int getint()
{
	int o = 0; char c = getchar();
	while (c>='0' && c<='9'){o = (o<<1) + (o<<3) + c - '0'; c = getchar();}
	return o;
}
struct arr
{
	int i, p;
	arr(){}
	arr(int I, int P) {i = I; p = P;}
	inline bool operator < (const arr & _) const
	{
		return (p > _.p) || (p == _.p && i < _.i);
	}
}f[N];
set<arr> F[N];

inline void init()
{
	n = getint(); m = getint(); q = getint();
	rep(i,1,n)
	{
		// scanf("%d",&p[i]);
		p[i] = getint();
		f[i] = arr(i,1);
		belong[i] = 0; visit[i] = 0; sta[i] = 0;
	}
	l = 1;
	rep(i,1,m)
	{
		// scanf("%d%d",&a[i],&b[i]);
		a[i] = getint(); b[i] = getint();
		is_alive[i] = 1;
		nex[++l] = sta[a[i]]; sta[a[i]] = l; e[l] = b[i];
		nex[++l] = sta[b[i]]; sta[b[i]] = l; e[l] = a[i];
	}
	rep(i,1,q)
	{
		// scanf("%d%d",&cmd[i],&key[i]);
		cmd[i] = getint(); key[i] = getint();
		if (cmd[i] == 2) is_alive[key[i]] = 0; else lastq=i;
	}
}

inline int getf(int x)
{
	if (f[x].i == x) return x;
	return f[x].i = getf(f[x].i);
}

inline void solve_back()
{
	int i, u, v;
	rep(i,1,m) if (is_alive[i])
	{
		u = getf(a[i]); v = getf(b[i]);
		f[u].i = v; f[v].p += f[u].p; f[u].p = 0;
	}
	drep(i,q,1) if (cmd[i] == 2)
	{
		u = getf(a[key[i]]); v = getf(b[key[i]]);
		if (u == v) {a[key[i]] = b[key[i]] = 0;} else
		{
			if (f[u].p > f[v].p)
			{
				swap(a[key[i]], b[key[i]]); swap(u,v);
			}
			f[u].i = v; f[v].p += f[u].p; f[u].p = 0;
		}
	}
}

inline void dfs(int x, int t)
{
	if (p[x]) {F[belong[x]].erase(arr(x,p[x])); F[t].insert(arr(x,p[x])); }
	belong[x] = t;
	for (int j = sta[x]; j; j = nex[j]) if (is_alive[j>>1] && visit[e[j]]!=t)
	{
		visit[e[j]] = t; dfs(e[j], t);
	}
}
inline void solve()
{
	int i, u, v, j, t, ans;
	set <arr> :: iterator pos;
	rep(i,1,m) is_alive[i] = 1;
	tot = 0;
	rep(i,1,n) if (visit[i] == 0)
	{
		++tot; F[tot].clear();
		dfs(i,tot);
	}
	rep(i,1,lastq)
	{
		// if (i > 100000){printf("FUCK%d\n",i); break;}
		if (cmd[i] == 1)
		{
			v = key[i]; t = belong[v]; ans = 0;
			if (F[t].size())
			{
				pos = F[t].begin();
				u = (*pos).i; ans = (*pos).p;
				F[t].erase(pos); p[u] = 0;
			}
			printf("%d\n",ans);
		}
		if (cmd[i] == 2)
		{
			u = a[key[i]]; v = b[key[i]];  is_alive[key[i]] = 0;
			if (u > 0 && v > 0)
			{
				++tot; F[tot].clear();
				dfs(u,tot);
			}
		}
	}
}
int main()
{
	// freopen("1.in","r",stdin); freopen("1.out","w",stdout);
	init();
	solve_back();
	solve();
	// fclose(stdin); fclose(stdout);
	return 0;
}

#include<bits/stdc++.h>

using namespace std;

#define  GODSPEED       ios:: sync_with_stdio(0);cin.tie(0);cout.tie(0);cout<<fixed;cout<<setprecision(15);
#define  f              first
#define  s              second
#define  newl           cout<<"\n";
#define  pb             push_back
#define  mset(a,x)      memset(a,x,sizeof(a))
#define  debv(a)        for(auto it: a)cout<<it<<" ";newl;
#define  deb1(a)        cout<<a<<"\n";
#define  deb2(a,b)      cout<<a<<" "<<b<<"\n";
#define  deb3(a,b,c)    cout<<a<<" "<<b<<" "<<c<<"\n";
#define  deb4(a,b,c,d)  cout<<a<<" "<<b<<" "<<c<<" "<<d<<"\n";
#define  uniq(a)        a.resize(unique(a.begin(), a.end()) - a.begin());
#define  all(a)         a.begin(),a.end()

typedef  long long             ll;
typedef  long double           ld;
typedef  pair<ll,ll>           pll;
typedef  vector<ll>            vll;
typedef  vector<pll>           vpll;

const ll   N     =  5e5+5;
const ll   M     =  4e6+5;
const ll   mod   =  1e9+7;
const ll   INF   =  0x7f7f7f7f7f7f7f7f;
const int  INFi  =  0x7f7f7f7f;

int n, m, q, a[N], u[N], v[N], rem[N], X[N], Y[N];
int p[N], sz[N], l[N], r[N], ind[N];
vll adj[N];

struct NODE{
	int val, ind;
	NODE(): val(), ind() {}
	NODE(int v, int i): val(v), ind(i){}
};

NODE tree[4*N+8];

NODE combine(NODE a, NODE b){
	NODE c;
	c.val = max(a.val, b.val);
	if(c.val == a.val) c.ind = a.ind;
	else c.ind = b.ind;
	return c;
}

void build(int node, int p, int start, int end){
	if(start == end){
		tree[node] = NODE(a[adj[p][start-1]], start);
	}
	else{
		int mid = (start + end) / 2;
		build(2*node, p, start, mid);
		build(2*node+1, p, mid+1, end);
		tree[node] = combine(tree[2*node], tree[2*node+1]);
	}
}

void update(int node, int start, int end, int idx){
	if(start == end){
		tree[node] = NODE(0, idx);
	}
	else{
		int mid = (start + end) / 2;
		if(start <= idx and idx <= mid)
			update(2*node, start, mid, idx);
		else
			update(2*node+1, mid+1, end, idx);
		tree[node] = combine(tree[2*node], tree[2*node+1]);
	}
}

NODE query(int node, int start, int end, int l, int r){
	if(start > end or start > r or end < l)
		return NODE();
	if(l <= start and end <= r)
		return tree[node];
	int mid = (start + end) / 2;
	NODE p1 = query(2*node, start, mid, l, r);
	NODE p2 = query(2*node+1, mid+1, end, l, r);
	return combine(p1, p2);
}

void make(ll n){
	for(int i = 1; i <= n; i++){
		p[i] = i;
		sz[i] = 1;
		adj[i].pb(i);
	}
}

int find(ll x){
	return (p[x] == x)? x: p[x] = find(p[x]);
}

void merge(ll x, ll y){
	ll a = find(x);
	ll b = find(y);
	if(a != b){
		if(sz[a] >= sz[b]) swap(a,b);
		p[a] = b;
		sz[b] += sz[a];
		for(auto it : adj[a]) adj[b].pb(it);
		adj[a].clear();
	}
}

void solve(){
	cin >> n >> m >> q;
	make(n);
	for(int i = 1; i <= n; i++) cin >> a[i];
	for(int i = 1; i <= m; i++) cin >> u[i] >> v[i];
	for(int i = 1; i <= q; i++){
		cin >> X[i] >> Y[i];
		if(X[i] == 2) rem[Y[i]] = 1;
	}
	for(int i = 1; i <= m; i++){
		if(rem[i] == 1) continue;
		merge(u[i], v[i]);
	}
	for(int i = q; i >= 1; i--){
		if(X[i] == 2) merge(u[Y[i]], v[Y[i]]);
		else{
			int x = find(Y[i]);
			l[i] = adj[x].front(), r[i] = adj[x].back();
		}
	}
	for(int i = 2; i <= n; i++) merge(1, i);
	int p = find(1);
	for(int i = 0; i < n; i++) ind[adj[p][i]] = i+1;
	build(1, p, 1, n);
	for(int i = 1; i <= q; i++){
		if(X[i] == 2) continue;
		NODE c = query(1, 1, n, ind[l[i]], ind[r[i]]);
		if(c.ind) update(1, 1, n, c.ind);
		deb1(c.val)
	}
}

int main(){
	GODSPEED;
	int test = 1;
	//cin >> test;
	for(int i = 1; i <= test; i++){
		solve();
	}
}

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
#define fi first
#define se second
#define lc (rt << 1)
#define rc ((rt << 1) | 1)
const int maxn = 2e6 + 50;
int INF = 1e8;
int n, m, q;
struct Edge
{
	int u, to, next;
} edge[maxn * 2], e[maxn];
int k, head[maxn];
void add(int a, int b){
	// printf("%d %d\n", a, b);
	edge[k].to = b;
	edge[k].next = head[a];
	head[a] = k++;
}

int fa[maxn];
int Find(int x){
	if(x == fa[x]) return x;
	return fa[x] = Find(fa[x]);
}

int tot;
void unit(int x, int y){
	x = Find(x), y = Find(y);
	if(x == y) return;
	tot++;
	fa[tot] = fa[x] = fa[y] = tot;
	add(tot, x);
	add(tot, y);
}

int p[maxn], vedge[maxn * 2];
pii qur[maxn];
int res[maxn];
int tim, intim[maxn], outim[maxn], id[maxn];

void dfs(int u, int pre){
	intim[u] = ++tim;
	id[tim] = u;
	for(int i = head[u]; i != -1; i = edge[i].next){
		int to = edge[i].to;
		if(to == pre) continue;
		dfs(to, u);
	}
	outim[u] = tim;
}

pii tree[maxn << 2];

void PushUp(int rt){
	tree[rt] = max(tree[lc], tree[rc]);
}
void Build(int le, int ri, int rt){
	if(le == ri){
		tree[rt] = {p[id[le]], le};
		// printf("le = %d p = %d\n", le, p[id[le]]);
		return ;
	}
	int mid = (le + ri) >> 1;
	Build(le, mid, lc);
	Build(mid + 1, ri, rc);
	PushUp(rt);
}

void Update(int le, int ri, int pos, int rt){
	if(le == ri){
		tree[rt] = {0, 0};
		return ;
	}
	int mid = (le + ri) >> 1;
	if(pos <= mid) Update(le, mid, pos, lc);
	else Update(mid + 1, ri, pos, rc);
	PushUp(rt);
}

pii Query(int le, int ri, int L, int R, int rt){
	if(L <= le && ri <= R){
		return tree[rt];
	}
	int mid = (le + ri) >> 1;
	pii tmp = {0, 0};
	if(L <= mid) tmp = max(tmp, Query(le, mid, L, R, lc));
	if(R > mid) tmp = max(tmp, Query(mid + 1, ri, L, R, rc));
	return tmp;
}

int main(int argc, char const *argv[])
{
	scanf("%d%d%d", &n, &m, &q);
	for(int i = 1; i <= 2 * n; i++) head[i] = -1, fa[i] = i;
	for(int i = 1; i <= n; i++) scanf("%d", &p[i]);
	for(int i = 1; i <= m; i++){
		int a, b;
		scanf("%d%d", &a, &b);
		e[i] = {a, b, 0};
	}
	for(int i = 1; i <= q; i++){
		int a, b;
		scanf("%d%d", &a, &b);
		qur[i] = {a, b};
		if(a == 2) vedge[b] = 1;
	}
	// printf("\n");
	tot = n;
	for(int i = 1; i <= m; i++){
		if(!vedge[i]){
			unit(e[i].u, e[i].to);
		}
	}
	for(int i = q; i >= 1; i--){
		if(qur[i].fi == 1){
			res[i] = Find(qur[i].se);
			// printf("res[%d] = \n", );
		} else {
			int x = qur[i].se;
			unit(e[x].u, e[x].to);
		}
	}
	for(int i = 1; i <= tot; i++){
		if(Find(i) == i){
			dfs(i, 0);
		}
	}
	// for(int i = 1; i <= tot; i++){
	// 	printf("intim[%d] = %d p = %d\n", i, intim[i], p[i]);
	// }
	Build(1, tot, 1);
	// printf("[%d %d]\n", tree[1].fi, tree[1].se);
	for(int i = 1; i <= q; i++){
		if(qur[i].fi == 1){
			int u = qur[i].se;
			u = Find(u);
			// printf("le = %d ri = %d\n", intim[u], outim[u]);
			pii tmp = Query(1, tot, intim[res[i]], outim[res[i]], 1);
			// printf("[%d %d]\n", tmp.fi, tmp.se);
			printf("%d\n", tmp.fi);
			if(tmp.fi == 0){
				continue;
			}
			Update(1, tot, tmp.se, 1);
		}
	}
	return 0;
}

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>

template <typename Tp> void read(Tp &res){
	static char ch; ch = getchar(), res = 0;
	while(!isdigit(ch)) ch = getchar();
	while(isdigit(ch)) res = res * 10 + ch - 48, ch = getchar();
}

const int MAXN = 2e5 + 19, MAXM = 3e5 + 19, MAXQ = 5e5 + 19;

int n, m, q, fa[MAXN], birth[MAXM], belong[MAXN], p[MAXN], opt[MAXQ], arg[MAXQ];
int getf(int node){return node == fa[node] ? node : fa[node] = getf(fa[node]);}
std::vector<int> mt[MAXN];
std::pair<int, int> G[MAXM];
bool vist[MAXM];

int main(){
	read(n), read(m), read(q);
	for(int i = 1; i <= n; ++i) read(p[i]), fa[i] = i, mt[i].push_back(i);
	for(int i = 1; i <= m; ++i) read(G[i].first), read(G[i].second);
	for(int i = 1; i <= q; ++i){
		read(opt[i]), read(arg[i]);
		if(opt[i] == 2) vist[arg[i]] = 1;
	}
	for(int i = 1; i <= m; ++i){
		if(vist[i]) continue;
		int a = G[i].first, b = G[i].second;
		a = getf(a), b = getf(b);
		if(a == b) continue;
		if(mt[a].size() < mt[b].size()) std::swap(a, b);
		for(int j : mt[b]) mt[a].push_back(j);
		std::vector<int>().swap(mt[b]);
		fa[b] = a;
	}
	for(int i = q; i >= 1; --i)
		if(opt[i] == 2){
			int a = G[arg[i]].first, b = G[arg[i]].second;
			a = getf(a), b = getf(b);
			if(a == b) continue;
			if(mt[a].size() < mt[b].size()) std::swap(a, b);
			birth[arg[i]] = b;
			for(int j : mt[b]) mt[a].push_back(j);
			fa[b] = a;
		}
	for(int i = 1; i <= n; ++i) belong[i] = getf(i), vist[i] = 0;
	for(int i = 1; i <= n; ++i) std::sort(mt[i].begin(), mt[i].end(), [](const int &a, const int &b){return p[a] < p[b];});
	for(int i = 1; i <= q; ++i){
		if(opt[i] == 1){
			int a = belong[arg[i]];
			while(!mt[a].empty() && (belong[mt[a].back()] != a || vist[mt[a].back()])) mt[a].pop_back();
			if(mt[a].empty()) puts("0");
			else printf("%d\n", p[mt[a].back()]), vist[mt[a].back()] = 1;
		}
		else{
			int a = birth[arg[i]];
			if(!a) continue;
			for(int j : mt[a]) belong[j] = a;
		}
	}
	return 0;
}

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int N=200005;
struct DSU
{
    vector<int> p;
    vector<int> sz;
    DSU(int n)
    {
        p.assign(n+1,0);
        for(int i=0;i<=n;i++) p[i]=i;
        sz.assign(n+1,1);
    }
    int find_set(int a)
    {
        if(a==p[a]) return a;
        else return p[a]=find_set(p[a]);
    }
    int merge_sets(int a,int b) //returns component with smaller size, or -1 if they are already connected
    {
        int origa=a;
        int origb=b;
        a=find_set(a);
        b=find_set(b);
        if(a==b) return -1;
        if(sz[a]<sz[b])
        {
            swap(a,b);
            swap(origa,origb);
        }
        p[b]=a;
        sz[a]+=sz[b];
        return origb;
    }
};

vector<array<int,2>> v[N];
vector<int> val(N,0);
vector<int> leader(N,0);
vector<set<int>> s(2*N);
int lidx=1;
int tnow=0;

void dfs1(int a,int l)
{
    leader[a]=l;
    s[l].insert(val[a]);
    for(auto [t,to]:v[a])
    {
        if(tnow>=t) break;
        if(leader[to]==0) dfs1(to,l);
    }
}

void dfs2(int a,int l,int r)
{
    leader[a]=l;
    if(val[a]!=0)
    {
        s[l].insert(val[a]);
        s[r].erase(val[a]);
    }
    for(auto [t,to]:v[a])
    {
        if(tnow>=t) break;
        if(leader[to]==r) dfs2(to,l,r);
    }
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n,m,q;
    cin >> n >> m >> q;
    vector<array<int,2>> edges(m+1,{0,0});
    DSU dsu(n);
    for(int i=1;i<=n;i++) cin >> val[i];
    for(int i=1;i<=m;i++)
    {
        int a,b;
        cin >> a >> b;
        edges[i]={a,b};
    }
    vector<bool> removed_edges(m+1,0);
    vector<array<int,2>> queries(q+1,{0,0});
    for(int i=1;i<=q;i++)
    {
        int t,a;
        cin >> t >> a;
        queries[i]={t,a};
        if(t==2) removed_edges[a]=1;
    }
    vector<int> disconnects(q+1,0); //0 if nothing is disconnected, the vertex with smaller current size otherwise
    for(int i=1;i<=m;i++)
    {
        if(removed_edges[i]==0)
        {
            auto [a,b]=edges[i];
            dsu.merge_sets(a,b);
            v[a].push_back({q+1,b});
            v[b].push_back({q+1,a});
        }
    }
    for(int i=q;i>=1;i--)
    {
        auto [t,a]=queries[i];
        if(t==1) continue;
        auto [c,d]=edges[a];
        int x=dsu.merge_sets(c,d);
        v[c].push_back({i,d});
        v[d].push_back({i,c});
        if(x!=-1) disconnects[i]=x;
    }
    for(int i=1;i<=n;i++) sort(v[i].begin(),v[i].end(),greater<array<int,2>>());
    for(int i=1;i<=n;i++)
    {
        if(leader[i]!=0) continue;
        dfs1(i,lidx++);
    }
    vector<bool> used(n+1,0);
    vector<int> h(n+1,0);
    for(int i=1;i<=n;i++) h[val[i]]=i;
    //set val[a]=0;
    for(int i=1;i<=q;i++)
    {
        tnow=i;
        auto [t,a]=queries[i];
        if(t==1)
        {
            int res=0;
            if(!s[leader[a]].empty())
            {
                int mx=(*s[leader[a]].rbegin());
                s[leader[a]].erase(mx);
                val[h[mx]]=0;
                res=mx;
            }
            cout << res << "\n";
        }
        else if(t==2)
        {
            int src=disconnects[i];
            if(src!=0) dfs2(src,lidx++,leader[src]);
        }
    }
    return 0;
}

#include <stdio.h>
#include <bits/stdc++.h>

using namespace std;

typedef double db;
typedef long long ll;
typedef long double ld;
typedef unsigned int ui;
typedef unsigned long long ull;

typedef pair < db, db > pdd;
typedef pair < db, ld > pdl;
typedef pair < ld, db > pld;
typedef pair < ld, ld > ldp;

typedef pair < ll, ll > pll;
typedef pair < int, ll > pil;
typedef pair < ll, int > pli;
typedef pair < int, int > pii;

#define F first
#define S second

#define en end()
#define bg begin()

#define rev reverse
#define mp make_pair
#define pb push_back

#define y1 y1234567890
#define um unordered_map

#define all(x) x.bg, x.en
#define sz(x) (int)x.size()
#define len(x) (int)strlen(x)

#define sqr(x) ((x + 0ll) * (x))
#define sqrd(x) ((x + 0.0) * (x))

#define forn(i, n) for (int i = 1; i <= n; i++)

const int inf = (int)1e9;
const ll mod = (ll)1e9 + 7;

const db eps = (db)1e-9;
const db pi = acos(-1.0);

const int dx[] = {0, 0, 1, 0, -1};
const int dy[] = {0, 1, 0, -1, 0};

const int N = 1000500;

pii t[N << 2];
bool er[N], u[N];
vector < int > g[N];
int timer, eu[N], tin[N], tout[N];
int n, m, q, a[N], e[N][2], tp[N], qr[N], ver[N], p[N];

int get(int v) {
	return (v == p[v] ? v : p[v] = get(p[v]));
}

void dfs(int v) {
	u[v] = 1;
	if (g[v].empty()) {
		eu[++timer] = v;
		tin[v] = tout[v] = timer;
		return;
	}
	tin[v] = inf;
	for (auto to : g[v]) {
		if (!u[to])
			dfs(to);
		tin[v] = min(tin[v], tin[to]);
		tout[v] = max(tout[v], tout[to]);
	}
}

void build(int v, int l, int r) {
	if (l == r) {
		t[v] = {a[eu[r]], r};
		return;
	}
	int mid = (l + r) >> 1;
	build(v << 1, l, mid);
	build(v << 1 | 1, mid + 1, r);
	t[v] = max(t[v << 1], t[v << 1 | 1]);
}

void upd(int v, int l, int r, int pos) {
	if (l == r) {
		t[v] = {0, r};
		return;
	}
	int mid = (l + r) >> 1;
	if (pos <= mid)
		upd(v << 1, l, mid, pos);
	else
		upd(v << 1 | 1, mid + 1, r, pos);
	t[v] = max(t[v << 1], t[v << 1 | 1]);
}

pii get(int v, int l, int r, int lx, int rx) {
	if (rx < l || r < lx)
		return {0, 0};
	if (lx <= l && r <= rx)
		return t[v];
	int mid = (l + r) >> 1;
	return max(get(v << 1, l, mid, lx, rx), get(v << 1 | 1, mid + 1, r, lx, rx));
}

int main() {
	//freopen(".in", "r", stdin);
	//freopen(".out", "w", stdout);
	//freopen(".err", "w", stderr);

	//mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());

	//cin.tie(NULL);
	//cout.tie(NULL);
	//ios_base::sync_with_stdio(false);

	//cout << setprecision(10) << fixed;

	scanf("%d %d %d", &n, &m, &q);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
		p[i] = i;
	}
	for (int i = 1; i <= m; i++)
		scanf("%d %d", &e[i][0], &e[i][1]);
	for (int i = 1; i <= q; i++) {
		scanf("%d %d", &tp[i], &qr[i]);
		if (tp[i] == 2)
			er[qr[i]] = 1;
	}

	for (int i = 1; i <= m; i++) {
		if (!er[i]) {
			q++;
			tp[q] = 2;
			qr[q] = i;
		}
	}

	int ptr = n;

	for (int i = q; i >= 1; i--) {
		if (tp[i] == 1)
			ver[i] = get(qr[i]);
		else {
			int x = get(e[qr[i]][0]);
			int y = get(e[qr[i]][1]);
			if (x != y) {
				++ptr;
				p[x] = p[y] = p[ptr] = ptr;
				g[ptr].pb(x);
				g[ptr].pb(y);
			}
		}
	}

	for (int i = ptr; i >= 1; i--) {
		if (!u[i])
			dfs(i);
	}
	build(1, 1, n);

	for (int i = 1; i <= q; i++) {
		if (tp[i] == 2) continue;
		pii res = get(1, 1, n, tin[ver[i]], tout[ver[i]]);
		printf("%d\n", res.F);
		upd(1, 1, n, res.S);
	}

	//cerr << (clock() + 0.0) / CLOCKS_PER_SEC;

	return 0;
}

#include <bits/stdc++.h>
using namespace std;
int n, m, q, ex[300011], ey[300011];
struct oper {
	int opt, s, sma, big;
	bool tree;
} a[500011];
int p[200011], siz[200011], fa[200011], belong[200011];
vector <int> h[200011]; //注意:因为p[i]为1~n的一个排列，所以vector中存储的是数，不是下标
bool del[300011], used[200011];
int find(int w) {
	if(fa[w] == w) return w;
	return find(fa[w]);
}
int query(int w) {
	while(h[w].size() && (belong[h[w].back()] != w || used[h[w].back()])) h[w].pop_back();
	if(!h[w].size()) return 0;
	int ret = h[w].back();
	h[w].pop_back(); used[ret] = 1;
	return ret;
}
int main() {
	scanf("%d%d%d", &n, &m, &q);
	for(int i = 1; i <= n; i++) {
		scanf("%d", &p[i]); fa[i] = i;
		h[i].push_back(p[i]); siz[i] = 1;
	}
	for(int i = 1; i <= m; i++)
		scanf("%d%d", &ex[i], &ey[i]);
	for(int i = 1; i <= q; i++) {
		scanf("%d%d", &a[i].opt, &a[i].s);
		if(a[i].opt == 2) del[a[i].s] = 1;
		a[i].tree = 0;
	}
	for(int i = 1; i <= m; i++) {
		if(del[i]) continue;
		int fx = find(ex[i]), fy = find(ey[i]);
		if(fx == fy) continue;
		if(siz[fx] < siz[fy]) swap(fx, fy);
		siz[fx] += siz[fy]; fa[fy] = fx;
		for(int j = 0; j < (int)h[fy].size(); j++)
			h[fx].push_back(h[fy][j]);
	}
	for(int i = q; i >= 1; i--) {
		if(a[i].opt == 2) {
			int fx = find(ex[a[i].s]), fy = find(ey[a[i].s]);
			if(fx == fy) continue;
			if(siz[fx] < siz[fy]) swap(fx, fy);
			a[i].big = fx; a[i].sma = fy;
			fa[fy] = fx; siz[fx] += siz[fy];
			for(int j = 0; j < (int)h[fy].size(); j++)
				h[fx].push_back(h[fy][j]);
			a[i].tree = 1;
		}
	}
	for(int i = 1; i <= n; i++) {
		sort(h[i].begin(), h[i].end());
		belong[p[i]] = find(i);
	}
	for(int i = 1; i <= q; i++) {
		if(a[i].opt == 1) printf("%d\n", query(find(a[i].s)));
		else if(a[i].tree) {
			for(int j = 0; j < (int)h[a[i].sma].size(); j++)
				belong[h[a[i].sma][j]] = a[i].sma;
			fa[a[i].sma] = a[i].sma;
		}
	}
	return 0;
}

#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
namespace FastIO {
    struct Reader {
    private:
        FILE* file; std::vector<char> buffer; int pos; bool was;
        void read() {
            if (!buffer.empty()) {
                buffer.resize(fread(&buffer[0], 1, (int)buffer.size(), file)); pos = 0;
            }
        }
    public:
        Reader(FILE* file_ = stdin, const int size_ = 1 << 16)
            : file(file_), buffer(size_, '\0'), pos(size_), was(true) { }
        operator bool() const { return was; }
        char getChar() {
            if (pos == (int)buffer.size()) { read(); }
            if (pos == (int)buffer.size()) { was = false; return EOF; }
            else { was = true; return buffer[pos++]; }
        }
        std::string getStr() {
            char c = ' ';
            while (std::isspace(c)) { c = getChar(); }
            std::string answ;
            while (c != EOF && !std::isspace(c)) { answ.push_back(c); c = getChar(); }
            was = !answ.empty();
            return answ;
        }
        std::string getLine() {
            char c = '\n';
            while (c == '\n') { c = getChar(); }
            std::string answ;
            while (c != '\n' && c != EOF) { answ.push_back(c); c = getChar(); }
            was = !answ.empty();
            return answ;
        }
        template<typename T> T getInt() {
            char c = '?';
            while (!(c == '-' || ('0' <= c && c <= '9') || c == EOF)) { c = getChar(); }
            bool positive = true;
            if (c == '-') { positive = false; c = getChar(); }
            T answ(0);
            bool flag = false;
            while ('0' <= c && c <= '9') { flag = true; (answ *= 10) += (c - '0'); c = getChar(); }
            was = flag;
            return positive ? answ : -answ;
        }
        template<typename T> T getReal() {
            bool flag = false;
            char c = '?';
            while (!(c == '-' || ('0' <= c && c <= '9') || c == EOF)) { c = getChar(); }
            bool positive = (c != '-');
            if (c == '-') { c = getChar(); }
            long long first = 0;
            while ('0' <= c && c <= '9') { flag = true; (first *= 10) += (c - '0'); c = getChar(); }
            was = flag;
            if (c != '.') { return T(positive ? first : -first); }
            c = getChar();
            long long second = 0, pow = 1;
            while ('0' <= c && c <= '9') { (second *= 10) += (c - '0'); c = getChar(); pow *= 10; }
            T answ = first + (T)second / (T)pow;
            return positive ? answ : -answ;
        }
    };

    Reader& operator>>(Reader& reader, char& c) { return c = reader.getChar(), reader; }

    Reader& operator>>(Reader& reader, std::string& s) { return s = reader.getStr(), reader; }

    template<class T> typename std::enable_if<std::is_floating_point<T>::value, Reader&>::type
    operator>>(Reader& reader, T& t) { return t = reader.getReal<T>(), reader; }

    template<class T> typename std::enable_if<std::is_integral<T>::value, Reader&>::type
    operator>>(Reader& reader, T& t) { return t = reader.getInt<T>(), reader; }

    template<class T> Reader& operator>>(Reader& reader, std::vector<T>& vec) {
        for (auto &it : vec) { reader >> it; }
        return reader;
    }

    struct Writer {
    private:
        FILE* file; std::vector<char> buffer; int pos;
        int defaultPrecision, defaultWidth; char defaultFill;
    public:
        Writer(FILE* file_ = stdout, const int size_ = 1 << 16)
            : file(file_), buffer(size_, '\0'), pos(0), defaultPrecision(6), defaultWidth(0), defaultFill(' ') { }
        ~Writer() { flush(); }
        void flush() { putChar(EOF); }
        void setprecision(int precision) { defaultPrecision = precision; }
        void setw(int width) { defaultWidth = width; }
        void setfill(char fill) { defaultFill = fill; }
        int getPrecision() const { return defaultPrecision; }
        int getWidth() const { return defaultWidth; }
        char getFill() const { return defaultFill; }
        void putChar(char c) {
            if (pos == (int)buffer.size() || c == EOF) {
                fwrite(&buffer[0], 1, pos, file); pos = 0;
            }
            if (c != EOF) { buffer[pos++] = c; }
        }
        void putStr(const std::string& s) { for (auto it : s) putChar(it); }
        template<typename T> void putInt(T value, int width = 0, char fill = ' ') {
            bool positive = !(value < 0);
            if (value < 0) { value = -value; }
            char buf[24]; int p = 0;
            do { buf[p++] = char(value % 10 + '0'); value /= 10; } while (value > 0);
            if (!positive) { buf[p++] = '-'; }
            while (p < width) buf[p++] = fill;
            while (p > 0) putChar(buf[--p]);
        }
        template<typename T> void putReal(T value, int precision = 6, int width = 0, char fill = ' ') {
            putInt((long long)value, width - precision - 1, fill);
            value = std::abs(value-(long long)value);
            if (precision == 0) { return; }
            putChar('.');
            #define PRINT_PART(cnt, pow) \
                while (precision >= cnt) { \
                    value *= pow; \
                    putInt((int)value, cnt, '0'); \
                    value -= (int)value; \
                    precision -= cnt; \
                }
            PRINT_PART(6,1000000)
            PRINT_PART(3,1000)
            PRINT_PART(1,10)
            #undef PRINT_PART
        }
    };

    Writer& operator<<(Writer& writer, const char c) { return writer.putChar(c), writer; }

    Writer& operator<<(Writer& writer, const std::string& s) { return writer.putStr(s), writer; }

    template<class T> typename std::enable_if<std::is_floating_point<T>::value, Writer&>::type
    operator<<(Writer& writer, const T& t) {
        writer.putReal(t, writer.getPrecision(), writer.getWidth(), writer.getFill());
        return writer;
    }

    template<class T> typename std::enable_if<std::is_integral<T>::value, Writer&>::type
    operator<<(Writer& writer, const T& t) {
        writer.putInt(t, writer.getWidth(), writer.getFill());
        return writer;
    }
}

using std::vector;
using std::string;
using ll = long long;
using real = long double;
using u64t = uint64_t;
using vi = vector<int>;
using vell = vector<ll>;
using vvi = vector<vi>;
using vvl = vector<vell>;
using pii = std::pair<int, int>;
using pll = std::pair<ll, ll>;
using vpii = vector<pii>;
using vpll = vector<pll>;
using vchar = vector<char>;
using vvchar = vector<vchar>;
#define isz(x) (int)(x).size()
#define all(x) begin(x), end(x)
#define forx(x, n) for(int x = 0; x < n; ++x)
#define forx1(x, n) for(int x = 1; x <= n; ++x)
#define fill(v, n) for(int i = 0; i < n; ++i) cin >> v[i];
const ll mod = 1e9 + 7;

template<class A, class B>
void remin(A &a, const B &b)
{
	a = (a < b) ? a : b;
}

template<class A, class B>
void remax(A &a, const B &b)
{
	a = (a > b) ? a : b;
}

ll gcd(ll a, ll b, ll & x, ll & y) {
	if (a == 0) {
		x = 0; y = 1;
		return b;
	}
	ll x1, y1;
	ll d = gcd(b%a, a, x1, y1);
	x = y1 - (b / a) * x1;
	y = x1;
	return d;
}

vi par;
vi sz;

int getParent(int x)
{
	if (par[x] == x) return x;
	return par[x] = getParent(par[x]);
}

struct decomp
{
	bool bridge = false;
	int lessComp;
	int lessCompSize;
};

void unite(int x, int y, decomp& cur, bool fictive = true)
{
	int par1 = getParent(x), par2 = getParent(y);
	if (par1 == par2) return;
	if (sz[par1] > sz[par2]) std::swap(x, y), std::swap(par1, par2);
	par[par1] = par2;
	if(!fictive) cur.bridge = true;
	if(!fictive) cur.lessComp = x;
	if (!fictive) cur.lessCompSize = sz[par1];
	sz[par2] += sz[par1];
}

vector<std::list<pii>> st;
vector<std::list<pii>::iterator> listIters;
vector<std::set<int>> adj, adj2;
vi p;
vi belongsTo;
int freeNum = 1;

std::list<pii> ficitveList;
static vi toDelete;
static vpii toNewList;
void divide(int x, int y, decomp& cur)
{
    toDelete.clear();
    toNewList.clear();
	int small = cur.lessComp;
	assert(small == x || small == y);
	int smallSize = cur.lessCompSize;
	//cout << small << " " << smallSize << "\n";
	int largeNum = belongsTo[small];
	std::unordered_map<int, int> used;
	std::queue<int> q;
	q.push(small);
	used[small] = 1;
	while(q.size())
	{
	    int u = q.front(); q.pop();
	    toDelete.push_back(u);
	    for(auto &v : adj2[u])
	    {
	        if(!used[v]) used[v] = 1, q.push(v);
	    }
	}
	for (auto &item : toDelete) belongsTo[item] = freeNum;
	for(auto &item : toDelete)
	{
	    auto it = listIters[item];
	    if(it == ficitveList.end()) continue;
	    toNewList.push_back(*it);
	    st[largeNum].erase(it);
	}
	std::sort(all(toNewList));
	for(auto &item : toNewList) st[freeNum].push_back(item);
	for(auto it = st[freeNum].begin(); it != st[freeNum].end(); ++it) listIters[(*it).second] = it;
	++freeNum;
}

int main()
{
    FastIO::Reader cin;
    FastIO::Writer cout;
    toDelete.reserve(2e5 + 10);
    toNewList.reserve(2e5 + 10);
	int n, m, q; cin >> n >> m >> q;
	par.resize(n + 1);
	std::iota(all(par), 0);
	belongsTo.resize(n + 1);
	st.resize(n + 2);
	sz.resize(n + 1, 1);
	listIters.resize(n + 2);
	p.resize(n + 1);
	adj.resize(n + 1);
	adj2.resize(n + 1);
	for (int u = 1; u <= n; ++u) cin >> p[u];
	vpii edges(m + 1);
	forx(i, m)
	{
		int u, v; cin >> u >> v;
		adj[u].insert(v); adj[v].insert(u);
		adj2[u].insert(v); adj2[v].insert(u);
		edges[i + 1] = { u, v };
	}
	vpii order(q);
	int deletedEdges = 0;
	forx(i, q)
	{
		int u, v; cin >> u >> v;
		order[i] = { u, v };
		if (u == 2) ++deletedEdges;
	}
	vector<decomp> events(deletedEdges);
	// Unite all after deleting edges
	for (auto &req : order)
	{
		if (req.first == 2)
		{
			auto it = edges[req.second];
			int u = it.first, v = it.second;
			adj[u].erase(v); adj[v].erase(u);
		}
	}
	decomp tmp{};
	for (int u = 1; u <= n; ++u) for (auto &v : adj[u]) unite(u, v, tmp);
	int ptr = 0;
	for (int i = order.size() - 1; i >= 0; --i)
	{
		if (order[i].first == 2)
		{
			auto it = edges[order[i].second];
			int u = it.first, v = it.second;
			unite(u, v, events[ptr], false);
			++ptr;
		}
	}
	std::reverse(all(events));
	vi used(n + 1, 0);
	vi curComponent;
	std::function<void(int)> dfs = [&](int u)
	{
		used[u] = 1;
		curComponent.push_back(u);
		for (auto &v : adj2[u]) if (!used[v]) dfs(v);
	};
	for (int u = 1; u <= n; ++u)
	{
		if (!used[u])
		{
			curComponent.clear();
			dfs(u);
			vpii tmp;
			for(auto &item : curComponent) tmp.push_back({p[item], item});
			std::sort(all(tmp));
			for(auto &item : tmp) st[freeNum].push_back(item);
			for(auto it = st[freeNum].begin(); it != st[freeNum].end(); ++it) listIters[(*it).second] = it;
			for (auto &item : curComponent) belongsTo[item] = freeNum;
			++freeNum;
		}
	}
	ptr = 0;
	forx(i, q)
	{
		if (order[i].first == 1)
		{
			int u = order[i].second;
			auto& curSet = st[belongsTo[u]];
			if (curSet.size())
			{
				auto it = --curSet.end();
				cout << it->first << "\n";
				listIters[it->second] = ficitveList.end();
				curSet.erase(it);
			}
			else cout << 0 << "\n";
		}
		else
		{
			auto it = edges[order[i].second];
			int u = it.first, v = it.second;
			adj2[u].erase(v); adj2[v].erase(u);
			if(events[ptr].bridge) divide(u, v, events[ptr]);
			++ptr;
		}
	}
	return 0;
}

#pragma GCC optimize("Ofast,unroll-loops")
#pragma GCC target("avx,avx2,fma")
#include <bits/stdc++.h>

using std::cin;
using std::cout;
using std::vector;
using std::string;
using ll = long long;
using real = long double;
using u64t = uint64_t;
using vi = vector<int>;
using vell = vector<ll>;
using vvi = vector<vi>;
using vvl = vector<vell>;
using pii = std::pair<int, int>;
using pll = std::pair<ll, ll>;
using vpii = vector<pii>;
using vpll = vector<pll>;
using vchar = vector<char>;
using vvchar = vector<vchar>;
#define isz(x) (int)(x).size()
#define all(x) begin(x), end(x)
#define forx(x, n) for(int x = 0; x < n; ++x)
#define forx1(x, n) for(int x = 1; x <= n; ++x)
#define fill(v, n) for(int i = 0; i < n; ++i) cin >> v[i];
const ll mod = 1e9 + 7;

ll fast_multip(ll a, ll b, ll m)
{
	if (!a || !b) return 0;
	if (b == 1) return a;
	if (a == 1) return b;
	if (b % 2 == 0) {
		long long t = fast_multip(a, b / 2, m);
		return (2 * t) % m;
	}
	return (fast_multip(a, b - 1, m) + a) % m;
}

ll fast_pow(ll a, ll b, ll m)
{
	if (b == 0)
		return (m == 1) ? 0 : 1;
	if (b % 2 == 0) {
		ll t = fast_pow(a, b / 2, m);
		return fast_multip(t, t, m) % m;
	}
	return (fast_multip(fast_pow(a, b - 1, m), a, m)) % m;
}

ll inv(ll a)
{
	return fast_pow(a, mod - 2, mod);
}

const auto ready = []()
{
	cin.tie(0);
	cout.tie(0);
	std::ios_base::sync_with_stdio(false);
	return true;
}();

template<class A, class B>
void remin(A &a, const B &b)
{
	a = (a < b) ? a : b;
}

template<class A, class B>
void remax(A &a, const B &b)
{
	a = (a > b) ? a : b;
}

ll gcd(ll a, ll b, ll & x, ll & y) {
	if (a == 0) {
		x = 0; y = 1;
		return b;
	}
	ll x1, y1;
	ll d = gcd(b%a, a, x1, y1);
	x = y1 - (b / a) * x1;
	y = x1;
	return d;
}

vi par;
vi sz;

int getParent(int x)
{
	if (par[x] == x) return x;
	return par[x] = getParent(par[x]);
}

struct decomp
{
	bool bridge = false;
	int lessComp;
	int lessCompSize;
};

void unite(int x, int y, decomp& cur, bool fictive = true)
{
	int par1 = getParent(x), par2 = getParent(y);
	if (par1 == par2) return;
	if (sz[par1] > sz[par2]) std::swap(x, y), std::swap(par1, par2);
	par[par1] = par2;
	if(!fictive) cur.bridge = true;
	if(!fictive) cur.lessComp = x;
	if (!fictive) cur.lessCompSize = sz[par1];
	sz[par2] += sz[par1];
}

vector<std::list<pii>> st;
vector<std::list<pii>::iterator> listIters;
vector<std::set<int>> adj, adj2;
vi p;
vi belongsTo;
int freeNum = 1;

std::list<pii> ficitveList;
static vi toDelete;
static vpii toNewList;
std::bitset<int(2e5 + 10)> used2;
void divide(int x, int y, decomp& cur)
{
    toDelete.clear();
    toNewList.clear();
	int small = cur.lessComp;
	assert(small == x || small == y);
	int smallSize = cur.lessCompSize;
	//cout << small << " " << smallSize << "\n";
	int largeNum = belongsTo[small];
	std::queue<int> q;
	q.push(small);
	used2[small] = 1;
	while(q.size())
	{
	    int u = q.front(); q.pop();
	    toDelete.push_back(u);
	    for(auto &v : adj2[u])
	    {
	        if(!used2[v]) used2[v] = 1, q.push(v);
	    }
	}
	used2 = 0;
	for (auto &item : toDelete) belongsTo[item] = freeNum;
	for(auto &item : toDelete)
	{
	    auto it = listIters[item];
	    if(it == ficitveList.end()) continue;
	    toNewList.push_back(*it);
	    st[largeNum].erase(it);
	}
	std::sort(all(toNewList));
	for(auto &item : toNewList) st[freeNum].push_back(item);
	for(auto it = st[freeNum].begin(); it != st[freeNum].end(); ++it) listIters[(*it).second] = it;
	++freeNum;
}

int main()
{
    toDelete.reserve(2e5 + 10);
    toNewList.reserve(2e5 + 10);
	int n, m, q; cin >> n >> m >> q;
	par.resize(n + 1);
	std::iota(all(par), 0);
	belongsTo.resize(n + 1);
	st.resize(n + 2);
	sz.resize(n + 1, 1);
	listIters.resize(n + 2);
	p.resize(n + 1);
	adj.resize(n + 1);
	adj2.resize(n + 1);
	for (int u = 1; u <= n; ++u) cin >> p[u];
	vpii edges(m + 1);
	forx(i, m)
	{
		int u, v; cin >> u >> v;
		adj[u].insert(v); adj[v].insert(u);
		adj2[u].insert(v); adj2[v].insert(u);
		edges[i + 1] = { u, v };
	}
	vpii order(q);
	int deletedEdges = 0;
	forx(i, q)
	{
		int u, v; cin >> u >> v;
		order[i] = { u, v };
		if (u == 2) ++deletedEdges;
	}
	vector<decomp> events(deletedEdges);
	// Unite all after deleting edges
	for (auto &req : order)
	{
		if (req.first == 2)
		{
			auto it = edges[req.second];
			int u = it.first, v = it.second;
			adj[u].erase(v); adj[v].erase(u);
		}
	}
	decomp tmp{};
	for (int u = 1; u <= n; ++u) for (auto &v : adj[u]) unite(u, v, tmp);
	int ptr = 0;
	for (int i = order.size() - 1; i >= 0; --i)
	{
		if (order[i].first == 2)
		{
			auto it = edges[order[i].second];
			int u = it.first, v = it.second;
			unite(u, v, events[ptr], false);
			++ptr;
		}
	}
	std::reverse(all(events));
	vi used(n + 1, 0);
	vi curComponent;
	std::function<void(int)> dfs = [&](int u)
	{
		used[u] = 1;
		curComponent.push_back(u);
		for (auto &v : adj2[u]) if (!used[v]) dfs(v);
	};
	for (int u = 1; u <= n; ++u)
	{
		if (!used[u])
		{
			curComponent.clear();
			dfs(u);
			vpii tmp;
			for(auto &item : curComponent) tmp.push_back({p[item], item});
			std::sort(all(tmp));
			for(auto &item : tmp) st[freeNum].push_back(item);
			for(auto it = st[freeNum].begin(); it != st[freeNum].end(); ++it) listIters[(*it).second] = it;
			for (auto &item : curComponent) belongsTo[item] = freeNum;
			++freeNum;
		}
	}
	ptr = 0;
	forx(i, q)
	{
		if (order[i].first == 1)
		{
			int u = order[i].second;
			auto& curSet = st[belongsTo[u]];
			if (curSet.size())
			{
				auto it = --curSet.end();
				cout << it->first << "\n";
				listIters[it->second] = ficitveList.end();
				curSet.erase(it);
			}
			else cout << 0 << "\n";
		}
		else
		{
			auto it = edges[order[i].second];
			int u = it.first, v = it.second;
			adj2[u].erase(v); adj2[v].erase(u);
			if(events[ptr].bridge) divide(u, v, events[ptr]);
			++ptr;
		}
	}
	return 0;
}

#include <bits/stdc++.h>
#include <ext/pb_ds/detail/standard_policies.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>

#define pb push_back
#define F first
#define S second
#define ll long long
#define ull unsigned long long
#define ld long double
#define endl '\n'
#define TIME 1.0*clock()/CLOCKS_PER_SEC
#define pii pair < int , int >
#define Endl '\n'

#pragma GCC optimize("Ofast")

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

template <typename T> using ordered_set = tree <T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;

mt19937 gen(chrono::system_clock::now().time_since_epoch().count());

const int mod = 1e9 + 7;
const ll FFTM = 998244353;

const int SX[4] = {0 , 1 , -1 , 0};
const int SY[4] = {1 , 0 , 0 , -1};
const int rx[8] = {1, -1, 0, 0, 1, 1, -1, -1};
const int ry[8] = {0, 0, 1, -1, 1, -1, 1, -1};
const int kx[8] = {1, 1, -1, -1, 2, 2, -2, -2};
const int ky[8] = {2, -2, 2, -2, 1, -1, 1, -1};

typedef cc_hash_table< int, int, hash<int>, equal_to<int>, direct_mask_range_hashing<int>, hash_standard_resize_policy<hash_exponential_size_policy<>, hash_load_check_resize_trigger<true>, true>> ht;

int n, m, q;

vector < int > pr;

vector < pii > quer;

vector < pii > all;

vector < int > a;

vector < bool > can;

vector < vector < int > > G;

vector < int > boss;
vector < int > tin;
vector < int > tout;

int timer = -1;

void init(){
    a.resize(n + q + m, 0);
    all.resize(n + q + m);
    quer.resize(n + q + m);
    can.resize(m, 1);
    pr.resize(n + q + m);
    for (int i = 0;i < n + q + m; ++i)pr[i] = i;
    G.resize(n + q + m);
    boss.resize(n + q + m, -1);
    tin.resize(n + q + m);
    tout.resize(n + q + m);
}

int find_pr(int v){
    if (pr[v] == v)return v;
    else return pr[v] = find_pr(pr[v]);
}

void add(int a, int b){
    a = find_pr(a);
    b = find_pr(b);
    if (a == b)return;
    pr[n] = n;
    pr[a] = n;
    pr[b] = n;
    G[n].pb(a);
    G[n].pb(b);
    n++;
}

void dfs(int v){
    timer++;
    tin[v] = timer;
    for (auto to : G[v]){
        dfs(to);
    }
    tout[v] = timer;
}

vector < pii > t;

void update(int v, int vl, int vr, int pos, pii val){
    if (vl == vr){
        t[v] = val;
        return;
    }
    int mid = (vl + vr) >> 1;
    if (pos <= mid)update(2 * v + 1, vl, mid, pos, val);
    else update(2 * v + 2, mid + 1, vr, pos, val);
    t[v] = max(t[2 * v + 1], t[2 * v + 2]);
}

pii get(int v, int vl, int vr, int l, int r){
    if (vl >= l && vr <= r)return t[v];
    if (vl > r || vr < l)return {0, 0};
    int mid = (vl + vr) >> 1;
    pii q1 = get(2 * v + 1, vl, mid, l, r);
    pii q2 = get(2 * v + 2, mid + 1, vr, l, r);
    return max(q1, q2);
}

int32_t main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#else
//    freopen("wedding.in", "r", stdin);
//    freopen("wedding.out", "w", stdout);
#endif
    cin >> n >> m >> q;
    init();
    for (int i = 0;i < n; ++i){
        cin >> a[i];
    }
    for (int i = 0;i < m; ++i){
        cin >> all[i].F >> all[i].S;
        all[i].F--;
        all[i].S--;
    }
    for (int i = 0;i < q; ++i){
        cin >> quer[i].F >> quer[i].S;
        quer[i].S--;
        if (quer[i].F == 2){
            can[quer[i].S] = 0;
        }
    }
    for (int i = 0;i < m; ++i){
        if (can[i]){
            add(all[i].F, all[i].S);
        }
    }
    for (int i = q - 1;i >= 0; --i){
        if (quer[i].F == 1){
            boss[i] = find_pr(quer[i].S);
        }else{
            add(all[quer[i].S].F, all[quer[i].S].S);
        }
    }
    for (int i = 0;i < n; ++i){
        if (find_pr(i) == i){
            dfs(i);
        }
    }
    t.resize(4 * n);
    for (int i = 0;i < n; ++i){
        update(0, 0, n - 1, tin[i], {a[i], tin[i]});
    }
    for (int i = 0;i < q; ++i){
        if (quer[i].F == 1){
            pii gt = get(0, 0, n - 1, tin[boss[i]], tout[boss[i]]);
            cout << gt.F << endl;
            if (gt.F != 0)update(0, 0, n - 1, gt.S, {0, 0});
        }
    }
    return 0;
}

// chrono::system_clock::now().time_since_epoch().count()
#include<bits/stdc++.h>

#define pb push_back
#define eb emplace_back
#define mp make_pair
#define fi first
#define se second
#define all(x) (x).begin(), (x).end()
#define debug(x) cerr << #x << " = " << x << endl;

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int MAXN = (int)5e5 + 5;
const int MAXM = (int)3e5 + 5;
const int MAXQ = (int)5e5 + 5;

pii e[MAXM], que[MAXQ], t[MAXN << 2];
vector<int> adj[MAXN];
int tin[MAXN], tout[MAXN], timer;
int par[MAXN], arr[MAXN];
bool del[MAXM];
int n, m, q;

int getPar(int x) {
	if (x == par[x]) {
		return x;
	}

	return par[x] = getPar(par[x]);
}

void uni(int a, int b) {
	a = getPar(a);
	b = getPar(b);

	if (a == b) {
		return;
	}

	++n;
	par[n] = n;
	par[a] = n;
	par[b] = n;
	adj[n].pb(a);
	adj[n].pb(b);
}

void dfs(int v) {
	tin[v] = ++timer;

	for (int to : adj[v]) {
		dfs(to);
	}

	tout[v] = timer;
}

pii segMax(int v, int tl, int tr, int l, int r) {
	if (l > r || tl > r || tr < l) {
		return mp(0, 0);
	}

	if (l <= tl && tr <= r) {
		return t[v];
	}

	int mid = (tl + tr) >> 1;
	int c1 = (v << 1), c2 = (c1 | 1);

	return max(segMax(c1, tl, mid, l, r), segMax(c2, mid + 1, tr, l, r));
}

void updPos(int v, int tl, int tr, int p, pii x) {
	if (tl == tr) {
		t[v] = x;
		return;
	}

	int mid = (tl + tr) >> 1;
	int c1 = (v << 1), c2 = (c1 | 1);

	if (p <= mid) {
		updPos(c1, tl, mid, p, x);
	}
	else {
		updPos(c2, mid + 1, tr, p, x);
	}

	t[v] = max(t[c1], t[c2]);
}

void solve() {
	scanf("%d %d %d", &n, &m, &q);

	for (int i = 1; i <= n; ++i) {
		scanf("%d", &arr[i]);
	}

	for (int i = 1; i <= m; ++i) {
		int u, v;
		scanf("%d %d", &u, &v);
		e[i] = mp(u, v);
	}

	for (int i = 1; i <= q; ++i) {
		int a, b;
		scanf("%d %d", &a, &b);
		que[i] = mp(a, b);

		if (a == 2) {
			del[b] = 1;
		}
	}

	for (int i = 1; i <= n; ++i) {
		par[i] = i;
	}

	for (int i = 1; i <= m; ++i) {
		if (!del[i]) {
			uni(e[i].fi, e[i].se);
		}
	}

	for (int i = q; i > 0; --i) {
		int tp = que[i].fi;

		if (tp == 2) {
			int id = que[i].se;
			uni(e[id].fi, e[id].se);
		}
		else {
			que[i].se = getPar(que[i].se);
		}
	}

	for (int i = 1; i <= n; ++i) {
		if (getPar(i) == i) {
			dfs(i);
		}
	}

	for (int i = 1; i <= n; ++i) {
		updPos(1, 1, n, tin[i], mp(arr[i], tin[i]));
	}

	for (int i = 1; i <= q; ++i) {
		int tp = que[i].fi;

		if (tp == 1) {
			int v = que[i].se;
			pii tmp = segMax(1, 1, n, tin[v], tout[v]);

			if (tmp.fi == 0) {
				printf("0\n");
			}
			else {
				printf("%d\n", tmp.fi);
				updPos(1, 1, n, tmp.se, mp(0, 0));
			}
		}
	}
}

int main() {
	int tt = 1;

	while (tt--) {
		solve();
	}

	return 0;
}

/*
    Автор кода: Вадим Зинов (zv.proger@yandex.ru)
    Решение задачи A с сайта codeforces.com
*/

#include<bits/stdc++.h>
using namespace std;

#define ALL(first) first.begin(), first.end()
#define FASTIO cin.tie(0); cout.tie(0); ios::sync_with_stdio(0)

using st = size_t;
using pii = pair<int, int>;

inline int readInt() {
    int x = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-')  f = -1; ch = getchar();}
    while(isdigit(ch)) {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar();}
    return x * f;
}

inline void writeInt(const int &a, const char &c) {
    printf("%d%c", a, c);
}

struct tree_of_segments {
    // Структура "Дерево отрезков" с получением и удалением максимума на отрезке
    struct seg_nd;
    st _n;
    seg_nd *root;

    struct seg_nd {
        pii mx = {-1, -1}; // mx значение и индекс
        seg_nd *ln = nullptr, *rn = nullptr;

        void set(int i, int v, int l, int r) {
            if (r - l == 1) {
                mx = {v, i}; return;
            }

            if (!rn) {
                ln = new seg_nd();
                rn = new seg_nd();
            }

            int m = (l + r) / 2;
            if (i < m) ln -> set(i, v, l, m);
            else rn -> set(i, v, m, r);

            mx = max(ln -> mx, rn -> mx);
        }

        pii get_mx (int ls, int rs, int l, int r) {
            if (ls <= l && rs >= r) return mx;
            if (ls >= r || rs <= l) return {-1, -1};
            if (!rn) return {-1, -1};
            int m = (l + r) / 2;
            return max(ln -> get_mx(ls, rs, l, m), rn -> get_mx(ls, rs, m, r));
        }
    };

    tree_of_segments(st n) {
        _n = n;
        root = new seg_nd;
    }

    void set(int i, int v) {
        root -> set(i, v, 0, _n);
    }

    pii mx(int ls, int rs) {
        return root -> get_mx(ls, rs, 0, _n);
    }

    pii mx(pii seg) {
        return root -> get_mx(seg.first, seg.second, 0, _n);
    }
};

vector<vector<int>> gr;

struct dsu {
    // Структура "Система непересекающихся множеств"
    // Позволяет за O(~1) объединять два множества
    // Позволяет за O(~1) находить корень множества
    // Позволяет за O(~1) отвечать, находятся ли 2 эл в одном множестве
    // Не позволяет разделять множества
    // Требует O(N) памяти

    vector<int> _par;
    st _n;

    dsu(st n) {
        // Инициализация за O(N)
        // Записывает каждый элемент в свое множество
        _n = n;
        _par.resize(n + 1);
        for (st i = 1; i <= n; i++) {
            _par[i] = i;
        }
    }

    int par/*ent*/(int i) {
        // Находит корень множества за O(~1)
        // Используется эвристика сжатия, что не позволяет создовать
        //  дерево с большой высотой (во всяком случае лениво ее сжимает)
        //  отсюда O(N) - в случае бамбука -> O(~1)
        if (_par[i] == i) return i;
        return _par[i] = par(_par[i]);
    }

    int uni/*on*/(int a, int b) {
        // Объединяет два множества (если они еще не объединены) за O(~1)
        // Вернет корень от полученного множества
        // Из-за специфичности задачи будут создаваться фиктивные вершины
        // Каждая вершниа - состояние графа в нек момент
        a = par(a); b = par(b);
        if (a == b) return a;
        gr.push_back({a, b});
        _par.push_back(++_n);
        _par[a] = _par[b] = _n;
        return _n;
    }

    int uni/*on*/(pii e) {
        return uni(e.first, e.second);
    }
};

void solve() {
    st n = readInt(), m = readInt(), q = readInt();

    gr.resize(n + 1);

    // Читаем значения на вершнинах (ps)
    vector<int> ps(n + 1);
    for (st i = 1; i <= n; i++)
        ps[i] = readInt();

    // Читаем ребра (es)
    vector<pii> es(m + 1);
    for (st i = 1; i <= m; i++)
        es[i].first = readInt(), es[i].second = readInt();

    // Читаем запросы (qs), es_to_del для дополнения
    // списка запросов удалением оставшихся ребер
    vector<bool> es_to_del(m + 1, true);
    vector<pii> qs(q);
    for (st i = 0; i < q; i++) {
        qs[i].first = readInt();
        qs[i].second = readInt();
        if (qs[i].first == 2) es_to_del[qs[i].second] = false;
    }

    // Дополняем qs запросами на удаление неудаленных ребер
    for (st i = 1; i <= m; i++) {
        if (es_to_del[i]) {
            qs.push_back({2, i});
            q++;
        }
    }

    // Это стек запросов на вывод наибольшего в компоненте
    vector <int> q1s;

    // Разворачиваем список запросов и по нему строим дерево СНМ (snm)
    reverse(ALL(qs));
    dsu snm(n);

    for (auto q: qs) {
        switch (q.first) {
            case 1: // если идет запрос на наибольшее значение - сохраняем "позицию" запроса
                q1s.push_back(snm.par(q.second));
                break;
            case 2: // Добавляем ребро в структуру
                snm.uni(es[q.second]);
        }
    }
    reverse(ALL(q1s));

    // snm построена, теперь для каждого запроса ответом будет наибольшее
    //  значение на вершине в поддереве snm записанного в q1s
    //  но проход по всему поддереву все еще долгое занятие, поэтому
    //  преобразуем snm к ДО следущим образом
    // 1) В порядке эйлерова обхода листья занесем в ДО
    // 2) Заменим вершины из q1s на параметры отрезка который они образуют
    // Теперь получение и удаление максимума будет за O(NLogN)

    tree_of_segments seg(n);
    vector<pii> segs(snm._n + 1, {-1, -1});
    int lst = 0;

    function<void (int)> dfs = [&](int v) {
        if (segs[v] != pii(-1, -1))
            return;
        segs[v].first = lst;
        if ((st) v <= n) seg.set(lst++, ps[v]);
        for (auto &u: gr[v])
            dfs(u);
        segs[v].second = lst;
    };

    for (st i = 1; i <= n; i++) {
        dfs(snm.par(i));
    }

    // Инициировали ДО. Наконец можно переходить к обработке запросов и выводу ответов

    for (auto &x: q1s) {
        auto p = seg.mx(segs[x]);
        seg.set(p.second, 0);
        writeInt(p.first, '\n');
    }
}

int main() {
    FASTIO;
#ifndef LCL
    //freopen("input.txt","r", stdin);
    //freopen("output.txt","w", stdout);
#endif

    int t = 1;
    for (; t--;) {
        solve();
    }
}

#include<bits/stdc++.h>

using namespace std;
const int N=5e5+5;
const int B=20;

vector<int>vc[N];
int dfn[N],seq[N],anc[N][B+1],out[N];
int idc;
void dfs(int u){
	dfn[u]=++idc;
	seq[idc]=u;
	for(int i=1;i<=B;i++)
		anc[u][i]=anc[anc[u][i-1]][i-1];
	for(auto v:vc[u]){
		anc[v][0]=u;
		dfs(v);
	}
	out[u]=idc;
}

#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r

struct nod{
	int val,pos;
}tree[N<<2];
int a[N];
nod max(nod a,nod b){
	if(a.val>b.val)return a;
	if(a.val<b.val)return b;
	return seq[a.pos]<seq[b.pos]?a:b;
}

void upda(const int &o){
	tree[o]=max(tree[o<<1],tree[o<<1|1]);
}
void build(int o,int l,int r){
	if(l==r){tree[o].val=a[seq[l]];tree[o].pos=l;return ;}
	int mid=(l+r)>>1;
	build(lson);build(rson);
	upda(o);
}
void modify(int o,int l,int r,int pos){
	if(l==r){tree[o].val=0;return ;}
	int mid=(l+r)>>1;
	if(pos<=mid)modify( lson , pos );
	if(pos >mid)modify( rson , pos );
	upda(o);
}
nod query(int o,int l,int r,int L,int R){
	if(L<=l&&r<=R)return tree[o];
	int mid=(l+r)>>1;
	nod ans;ans.val=0;ans.pos=l;
	if(L<=mid)ans=max(ans,query(lson,L,R));
	if(R >mid)ans=max(ans,query(rson,L,R));
	return ans;
}

int n,m,q,xx,yy,fx,fy,tot;
int ssiz[N],f[N],tim[N];
struct bian{
	int fr,to;
}e[N];
struct RW{
	int opt,id;
}rw[N];
bool ban[N];
int find(int x){
	if(x==f[x])return x;
	return f[x]=find(f[x]);
}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&xx,&yy);
		e[i].fr=xx;
		e[i].to=yy;
	}
	for(int i=1;i<=q;i++){
		scanf("%d%d",&xx,&yy);
		rw[i].opt=xx;
		rw[i].id=yy;
		if(rw[i].opt==2)ban[rw[i].id]=1;
	}
	for(int i=1;i<=n*2;i++){
		f[i]=i;ssiz[i]=(i<=n);
	}
	for(int i=1;i<=m;i++){
		if(ban[i])continue;
		fx=find(e[i].fr);
		fy=find(e[i].to);
		if(fx==fy)continue;
		f[fx]=fy;ssiz[fy]+=ssiz[fx];
	}
	tot=n;
	for(int i=1;i<=n;i++){
		if(ssiz[find(i)]==1) continue;
		if(find(i)==i){f[i]=++tot;tim[tot]=q+1;}
	}
	for(int i=1;i<=n;i++){
		if(find(i)==i)continue;
		vc[find(i)].push_back(i);
	}
	for(int i=q;i>=1;i--){
		if(rw[i].opt==1)continue;
		fx=find(e[rw[i].id].fr);
		fy=find(e[rw[i].id].to);
		if(fx==fy)continue;
		++tot;
		f[fx]=f[fy]=tot;
		vc[tot].push_back(fx);
		vc[tot].push_back(fy);
		tim[tot]=i;
	}
	//cout<<"n*2 "<<n*2<<endl;
	//cout<<"tot "<<tot<<endl;
	for(int i=1;i<=tot;i++){
		if(find(i)==i){
			dfs(i);
		}
	}
	//idc=n*2;
	build(1,1,idc);
	for(int i=1;i<=q;i++){
		if(rw[i].opt==2)continue;
		int u=rw[i].id;
		for(int j=B;j>=0;j--){
			if(tim[anc[u][j]]>=i)u=anc[u][j];
		}
		nod tmp=query(1,1,idc,dfn[u],out[u]);
		if(tmp.val)modify(1,1,idc,tmp.pos);
		printf("%d\n",tmp.val);
	}
	return 0;
}
/*
#include<bits/stdc++.h>

using namespace std;
const int N=4e2+5;
const int B=25;

vector<int>vc[N];
int dfn[N],seq[N],anc[N][B+2],out[N];
int idc;
void dfs(int u){
	dfn[u]=++idc;
	seq[idc]=u;
	for(int i=1;i<=B;i++)
		anc[u][i]=anc[anc[u][i-1]][i-1];
	for(auto v:vc[u]){
		anc[v][0]=u;
		dfs(v);
	}
	out[u]=idc;
}

#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r

struct nod{
	int val,pos;
}tree[N<<2];
int a[N];
nod max(nod a,nod b){
	if(a.val>b.val)return a;
	if(a.val<b.val)return b;
	return seq[a.pos]<seq[b.pos]?a:b;
}

void upda(const int &o){
	tree[o]=max(tree[o<<1],tree[o<<1|1]);
}
void build(int o,int l,int r){
	if(l==r){tree[o].val=a[seq[l]];tree[o].pos=l;return ;}
	int mid=(l+r)>>1;
	build(lson);build(rson);
	upda(o);
}
void modify(int o,int l,int r,int pos){
	if(l==r){tree[o].val=0;return ;}
	int mid=(l+r)>>1;
	if(pos<=mid)modify(lson,pos);
	if(pos >mid)modify(rson,pos);
	upda(o);
}
nod query(int o,int l,int r,int L,int R){
	if(L<=l&&r<=R)return tree[o];
	int mid=(l+r)>>1;
	nod ans;ans.val=0;ans.pos=l;
	if(L<=mid)ans=max(ans,query(lson,L,R));
	if(R >mid)ans=max(ans,query(rson,L,R));
	return ans;
}

int n,m,q,xx,yy,fx,fy,tot;
int ssiz[N],f[N],tim[N];
struct bian{
	int fr,to;
}e[N];
struct RW{
	int opt,id;
}rw[N];
bool ban[N];
int find(int x){
	if(x==f[x])return x;
	return f[x]=find(f[x]);
}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&xx,&yy);
		e[i].fr=xx;
		e[i].to=yy;
	}
	for(int i=1;i<=q;i++){
		scanf("%d%d",&xx,&yy);
		rw[i].opt=xx;
		rw[i].id=yy;
		if(rw[i].opt==2)ban[rw[i].id]=1;
	}
	for(int i=1;i<=n*2;i++){
		f[i]=i;ssiz[i]=(i<=n);
	}
	for(int i=1;i<=m;i++){
		if(ban[i])continue;
		fx=find(e[i].fr);
		fy=find(e[i].to);
		if(fx==fy)continue;
		f[fx]=fy;ssiz[fy]+=ssiz[fx];
	}
	tot=n;
	for(int i=1;i<=n;i++){
		if(ssiz[find(i)]==1) continue;
		if(find(i)==i){f[i]=++tot;tim[tot]=q+1;}
	}
	for(int i=1;i<=n;i++){
		if(find(i)==i)continue;
		vc[find(i)].push_back(i);
	}
	for(int i=q;i>=1;i--){
		if(rw[i].opt==1)continue;
		fx=find(e[rw[i].id].fr);
		fy=find(e[rw[i].id].to);
		if(fx==fy)continue;
		++tot;
		f[fx]=f[fy]=tot;
		vc[tot].push_back(fx);
		vc[tot].push_back(fy);
		tim[tot]=i;
	}
	for(int i=1;i<=tot;i++){
		if(find(i)==i){
			dfs(i);
		}
	}
	build(1,1,idc);
	for(int i=1;i<=q;i++){
		if(rw[i].opt==2)continue;
		int u=rw[i].id;
		for(int j=0;j<=B;j++){
			if(tim[anc[u][j]]>=i)u=anc[u][j];
		}
		//printf("%d\n",u);
		nod tmp=query(1,1,idc,dfn[u],out[u]);
		modify(1,1,idc,tmp.pos);
		printf("%d\n",tmp.val);
	}
	return 0;
}
*/

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

#include <bits/stdc++.h>

using namespace std;

#define POW2(X) (1<<(X))
#define CKBIT(S,X) (((S)&POW2(X))!=0)
const double pi=acos(-1.0);
const double eps=1e-11;
template<class T> inline void ckmin(T &a,T b){ a=min(a,b); }
template<class T> inline void ckmax(T &a,T b){ a=max(a,b); }
template<class T> inline T sqr(T x){ return x*x; }
#define SIZE(A) ((int)A.size())
#define LENGTH(A) ((int)A.length())
#define MP(A,B) make_pair(A,B)
#define PB(X) push_back(X)
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,a) for(int i=0;i<(a);++i)
#define ALL(A) A.begin(),A.end()
using uint=unsigned int;
using int64=long long;
using uint64=unsigned long long;
using ipair=pair<int,int>;
using VI=vector<int>;
using VD=vector<double>;

class UnionFind {
 public:
  UnionFind(int n) {
	  groups_ = std::vector<int>(n, -1);
  }

  int Find(int p) {
	  int r = p;
	  while (groups_[r] >= 0) r = groups_[r];
	  int t = groups_[p];
	  while (t >= 0) {
		groups_[p] = r;
		p = t;
		t = groups_[p];
	  }
	  return r;
  }

  std::vector<int> groups_;
};

struct Query
{
    int tp;
    int key;
    int ret;
};
struct Edge
{
    int u;
    int v;
};

struct Range
{
	int s = 0;
	int t = -1;
	Range() = default;
	Range(int s, int t) : s(s), t(t) { }

	int size() const { return t - s + 1; }
	bool has_overlap(const Range& other_range) const { return s <= other_range.t && t >= other_range.s; }
	bool is_contain(const Range& other_range) const { return s <= other_range.s && t >= other_range.t; }
};

struct Node
{
	Range range;
	Node* left_child;
	Node* right_child;

	// Data
	ipair max_val;

	void init(Range _range)
	{
		range = _range;
		max_val = MP(0, range.s);
	}
	void pop()
	{
		if (range.s == range.t) { assert(left_child == nullptr && right_child == nullptr); return; }
		assert(left_child != nullptr && right_child != nullptr);
		const Node& l = *left_child;
		const Node& r = *right_child;
		max_val = max(l.max_val, r.max_val);
	}
	void push()
	{
	}

	int size() const { return range.size(); }
	int mid() const { return (range.s + range.t) / 2; }
};

class IntervalTree
{
public:
	void build(int min_idx, int max_idx)
	{
		assert(min_idx <= max_idx);
		int size = max_idx - min_idx + 1;
		for (; size & (size - 1); size += (size & (-size)));
		reset_buffer(size * 2);
		root = build_internal(min_idx, max_idx);
	}

	template<class Func>
	void traverse(const Range& range, Func func)
	{
		traverse_internal(range, func, 0);
	}

	template<class Func>
	void traverse_in_reverse_order(const Range& range, Func func)
	{
		traverse_internal(range, func, 1);
	}

	Node* root;

private:
	template<class Func>
	void traverse_internal(const Range& range, Func func, int reverse_order)
	{
		assert(root != nullptr);
		if (!range.has_overlap(root->range)) return;
		traverse_nodes_internal(root, range, func, reverse_order);
	}

	template<class Func>
	void traverse_nodes_internal(Node* p, const Range& range, Func func, int reverse_order)
	{
		if (range.is_contain(p->range)) { func(p); return; }
		p->push();
		int m = p->mid();
		if (reverse_order)
		{
			if (m < range.t) traverse_nodes_internal(p->right_child, range, func, reverse_order);
			if (m >= range.s) traverse_nodes_internal(p->left_child, range, func, reverse_order);
		}
		else
		{
			if (m >= range.s) traverse_nodes_internal(p->left_child, range, func, reverse_order);
			if (m < range.t) traverse_nodes_internal(p->right_child, range, func, reverse_order);
		}
		p->pop();
	}

	Node* build_internal(int min_idx, int max_idx)
	{
		assert(buffer_pos < buffer.size());
		Node* p = &buffer[buffer_pos++];
		p->init(Range(min_idx, max_idx));
		if (min_idx == max_idx)
			p->left_child = p->right_child = nullptr;
		else
		{
			int m = (min_idx + max_idx) / 2;
			p->left_child = build_internal(min_idx, m);
			p->right_child = build_internal(m + 1, max_idx);
			p->pop();
		}
		return p;
	}

	void reset_buffer(int size)
	{
		buffer_pos = 0;
		buffer.clear();
		buffer.resize(size);
	}

	vector<Node> buffer;
	int buffer_pos;
};

int main()
{
#ifdef _MSC_VER
	freopen("input.txt","r",stdin);
#endif
	std::ios::sync_with_stdio(false);
    int n,m,nq;
    cin>>n>>m>>nq;
    VI val(n+m);
    REP(i,n) cin>>val[i];
    vector<Edge> e(m);
    REP(i,m) { cin>>e[i].u>>e[i].v; --e[i].u; --e[i].v; }
    vector<Query> q(nq);
    REP(i,nq) { cin>>q[i].tp>>q[i].key; --q[i].key; }
    VI deleted(m);
    REP(i,nq) if (q[i].tp==2) deleted[q[i].key]=1;
    UnionFind uf(n+m);
    int next_id=n;
    vector<VI> g(n+m);
    auto add=[&](int a,int b) {
        a=uf.Find(a);
        b=uf.Find(b);
        if (a==b) return;
        int c=(next_id++);
        uf.groups_[a]=uf.groups_[b]=c;
        g[c].push_back(a);
        g[c].push_back(b);
    };
    REP(i,m) if (!deleted[i]) add(e[i].u,e[i].v);
    for (int i=nq-1;i>=0;i--)
        if (q[i].tp==2)
            add(e[q[i].key].u,e[q[i].key].v);
        else
            q[i].key=uf.Find(q[i].key);
    VI que;
    VI idx(n+m,-1);
    VI last(n+m);
    std::function<void(int)> dfs=[&](int p) {
        idx[p]=SIZE(que);
        que.push_back(p);
        for (int x:g[p]) dfs(x);
        last[p]=SIZE(que)-1;
    };
	VI indeg(n+m);
	REP(i,n+m) for (int j:g[i]) ++indeg[j];
    REP(i,n+m) if (indeg[i]==0) dfs(i);
    VI a(n+m);
    REP(i,SIZE(que)) a[i]=val[que[i]];

	IntervalTree tree;
	tree.build(0,n+m-1);
	auto update=[&](int at,int val) {
		a[at]=val;
		tree.traverse(Range(at,at),[&](Node* node) { if (node->range.size()==1) node->max_val=MP(val,at); });
	};
	REP(i,n+m) update(i,a[i]);

    REP(k,nq)
        if (q[k].tp==1)
        {
            int s=idx[q[k].key];
            int t=last[q[k].key];
			ipair ret=MP(-1,-1);
			tree.traverse(Range(s,t),[&](Node* node) { ret=max(ret,node->max_val); });
			printf("%d\n",ret.first);
			int key=ret.second;
			update(key,0);
			/*
            int key=-1;
            FOR(i,s,t+1) if (key<0 || a[i]>a[key]) key=i;
            printf("%d\n",a[key]);
            a[key]=0;
			*/
        }
	return 0;
}

#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
#define rc(x) return cout<<x<<endl,0
#define pb push_back
#define mkp make_pair
#define in insert
#define er erase
#define fd find
#define fr first
#define sc second
#define all(x) x.begin(),x.end()
#define lun(x) (int)x.size()
typedef long long ll;
typedef long double ld;
const ll INF=0x3f3f3f3f3f3f3f3f;
const ll llinf=(1LL<<60);
const int inf=(1<<30);
const int nmax=5e5+50;
const ll mod=1e9+7;
using namespace std;
int n,m,q,i,sz,tt,x,y,ex[nmax],ey[nmax],vl[nmax],v[nmax],p[nmax],in[nmax],out[nmax],tp[nmax],gl[nmax],er[nmax],viz[nmax],nd[nmax];
vector<int>a[nmax];
pair<int,int>st[4*nmax],pr;
int fnd(int x)
{
    if(p[x]==x)return x;
    return p[x]=fnd(p[x]);
}
void uni(int x,int y)
{
    x=fnd(x),y=fnd(y);
    if(x==y)return;
    sz++;
    p[x]=sz;
    p[y]=sz;
    p[sz]=sz;
    a[sz].pb(x);
    a[sz].pb(y);
}
void dfs(int x)
{
    viz[x]=1;
    in[x]=++tt;
    nd[tt]=x;
    for(int i=0;i<lun(a[x]);i++)if(!viz[a[x][i]])dfs(a[x][i]);
    out[x]=tt;
}
void build(int nod,int l,int r)
{
	if(l==r)
	{
		st[nod]=mkp(v[nd[l]],l);
		return;
	}
	int mid=(l+r)/2;
	build(2*nod,l,mid);
	build(2*nod+1,mid+1,r);
	st[nod]=max(st[2*nod],st[2*nod+1]);
}
void upd(int nod,int l,int r,int p)
{
	if(l==r)
	{
		st[nod]=mkp(0,0);
		return;
	}
	int mid=(l+r)/2;
	if(p<=mid)upd(2*nod,l,mid,p);
	else upd(2*nod+1,mid+1,r,p);
	st[nod]=max(st[2*nod],st[2*nod+1]);
}
pair<int,int> qry(int nod,int l,int r,int tl,int tr)
{
	if(tr<l || tl>r)return mkp(0,0);
	if(tl<=l && r<=tr)return st[nod];
	int mid=(l+r)/2;
	return max(qry(2*nod,l,mid,tl,tr),qry(2*nod+1,mid+1,r,tl,tr));
}
int main()
{
	//freopen("sol.in","r",stdin);
	//freopen("sol.out","w",stdout);
	//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
	ios_base::sync_with_stdio(false);cin.tie(0);cerr.tie(0);cout.tie(0);
    cin>>n>>m>>q;
    for(i=1;i<=n;i++)cin>>v[i];
    for(i=1;i<=m;i++)cin>>ex[i]>>ey[i];
    for(i=1;i<=n;i++)p[i]=i;
    sz=n;
    for(i=1;i<=q;i++)
    {
        cin>>tp[i]>>vl[i];
        if(tp[i]==2)er[vl[i]]=1;
    }
    for(i=1;i<=m;i++)
    {
        if(er[i])continue;
        x=ex[i],y=ey[i];
        uni(x,y);
    }
    for(i=q;i>=1;i--)
    {
        if(tp[i]==1)gl[i]=fnd(vl[i]);
        else uni(ex[vl[i]],ey[vl[i]]);
    }
    for(i=sz;i>=1;i--)
    {
        if(viz[i])continue;
        dfs(i);
    }
    build(1,1,tt);
    for(i=1;i<=q;i++)
    {
        if(tp[i]==2)continue;
        x=gl[i];
        pr=qry(1,1,tt,in[x],out[x]);
        upd(1,1,tt,pr.sc);
        cout<<pr.fr<<'\n';
    }
	return 0;
}

#include <bits/stdc++.h>
/** #include <ext/pb_ds/assoc_container.hpp>
 * #include <ext/pb_ds/tree_policy.hpp>
 * using namespace __gnu_pbds; */
using namespace std;

#define ll long long
#define ull unsigned long long
#define f(a, b) for (ll i = a; i < b; i++)
#define mod 1000000007
#define pb push_back
#define vll vector<ll>
#define pll vector<pair<ll, ll>>
#define ld long double
#define fr(a, b) for (ll j = a; j >= b; j--)
#define fi(a, b) for (ll j = a; j < b; j++)
#define fii(a, b) for (ll k = a; k < b; k++)
/** typedef tree<ll
 * ,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>
 * ordered_set; */

template <class T> ostream &operator<<(ostream &os, vector<T> V) {
  os << "[ ";
  for (auto v : V)
    os << v << " ";
  os << "]";
  return os;
}
template <class T> ostream &operator<<(ostream &os, set<T> S) {
  os << "{ ";
  for (auto s : S)
    os << s << " ";
  return os << "}";
}
template <class L, class R> ostream &operator<<(ostream &os, map<L, R> M) {
  os << "{ ";
  for (auto m : M)
    os << "(" << m.first << ":" << m.second << ") ";
  return os << "}";
}
template <class L, class R> ostream &operator<<(ostream &os, pair<L, R> P) {
  return os << "(" << P.first << "," << P.second << ")";
}

const ll N = 200005;
ll p[N];
ll x[N << 1], y[N << 1];
bool removed[N << 1];
pll query;

struct DSU {

  vector<ll> a, s;
  pll changes;
  vector<set<ll>> elements;

  DSU(ll n) {
    a.resize(n + 1);
    s.resize(n + 1);
    elements.resize(n + 1);
    for (int i = 1; i <= n; i++) {
      a[i] = i;
      s[i] = 1;
      elements[i].insert(p[i]);
    }
  }

  ll root(ll i) {
    while (i != a[i]) {
      // a[i] = a[a[i]];
      i = a[i];
    }
    return i;
  }

  bool merge(ll x, ll y) {
    ll xr = root(x), yr = root(y);
    if (xr == yr) {
      changes.pb({xr, xr});
      return false;
    }
    if (s[xr] < s[yr])
      swap(xr, yr);
    s[xr] += s[yr];
    elements[xr].insert(elements[yr].begin(), elements[yr].end());
    a[yr] = xr;
    changes.pb({xr, yr});
    return true;
  }

  void rollBack() {
    if (changes.empty())
      return;
    pair<ll, ll> p = changes.back();
    ll xr = p.first, yr = p.second;
    changes.pop_back();
    if (xr == yr)
      return;
    for (auto it = elements[yr].begin(); it != elements[yr].end();) {
      if (elements[xr].find(*it) != elements[xr].end())
        elements[xr].erase(*it), it++;
      else
        it = elements[yr].erase(it);
    }
    a[yr] = yr;
    s[xr] = elements[xr].size();
    s[yr] = elements[yr].size();
  }

  ll query(ll x) {
    ll xr = root(x);
    if (elements[xr].empty())
      return 0;
    ll ret = *(--elements[xr].end());
    elements[xr].erase(--elements[xr].end());
    s[xr]--;
    return ret;
  }
};

int main() {
#ifndef ONLINE_JUDGE
  freopen("input.txt", "rt", stdin);
  freopen("output.txt", "wt", stdout);
#endif
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  set<ll> s;
  s.erase(5);
  ll n, m, q;
  cin >> n >> m >> q;
  f(1, n + 1) cin >> p[i];
  f(1, m + 1) cin >> x[i] >> y[i];
  query.resize(q);
  vll r;
  f(0, q) {
    cin >> query[i].first >> query[i].second;
    if (query[i].first == 2)
      removed[query[i].second] = true, r.pb(query[i].second);
  }
  DSU d(n);
  f(1, m + 1) {
    if (!removed[i])
      d.merge(x[i], y[i]);
  }
  reverse(r.begin(), r.end());
  f(0, r.size()) d.merge(x[r[i]], y[r[i]]);
  f(0, q) {
    if (query[i].first == 1)
      cout << d.query(query[i].second) << '\n';
    else
      d.rollBack();
  }

#ifndef ONLINE_JUDGE
  cout << "\nTime Elapsed : " << 1000 * (ld)clock() / (ld)CLOCKS_PER_SEC
       << " ms\n";
#endif
  return 0;
}

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<climits>
#include<bitset>
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=4e5+11;
int N,M,T[MAXN];vector<int> vec[MAXN];
struct Segment{
    int Maxn[MAXN<<2];
    void Modify(int k,int l,int r,int ps,int w){
        if(l==r){Maxn[k]=w;return;}
        int mid=(l+r)>>1;if(ps<=mid) Modify(k<<1,l,mid,ps,w);else Modify(k<<1|1,mid+1,r,ps,w);
        Maxn[k]=max(Maxn[k<<1],Maxn[k<<1|1]);return;
    }
    int Query(int k,int l,int r,int x,int y){
        //cerr<<"l:"<<l<<" r:"<<r<<" "<<x<<" "<<y<<endl;
        if(x<=l&&r<=y) return Maxn[k];int mid=(l+r)>>1,res=0;
        if(x<=mid) res=max(res,Query(k<<1,l,mid,x,y));
        if(mid<y) res=max(res,Query(k<<1|1,mid+1,r,x,y));
        return res;
    }
}S;
struct Edge{int u,v,tim;}E[MAXN];
bool cmp(Edge x1,Edge x2){return x1.tim>x2.tim;}
struct Union{
    int f[MAXN];void init(){for(int i=1;i<=2*N;i++) f[i]=i;return;}
    int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
}U;pii Que[MAXN];
int dfn[MAXN],siz[MAXN],INF=INT_MAX,MM[MAXN],Val[MAXN],dep[MAXN],tot,fa[MAXN][21],cnt,Q;
void dfs(int u,int fath){
    dep[u]=dep[fath]+1;fa[u][0]=fath;if(u<=N) siz[u]=1,dfn[u]=++dfn[0];
    for(int i=1;(1<<i)<=dep[u];i++) fa[u][i]=fa[fa[u][i-1]][i-1];
    for(auto v:vec[u]) if(v!=fath) dfs(v,u),siz[u]+=siz[v],dfn[u]=min(dfn[u],dfn[v]);return;
}
int Qmax(int u,int t){
    for(int i=20;i>=0;i--) if(T[fa[u][i]]>=t&&fa[u][i]) u=fa[u][i];
    return u;
}
int main(){
    //freopen("D.in","r",stdin);
    N=read(),M=read(),Q=read();U.init();tot=N;
    for(int i=1;i<=N;i++) Val[i]=read(),MM[Val[i]]=i;
    for(int i=1;i<=M;i++) E[i].u=read(),E[i].v=read(),E[i].tim=INF;int ps=0;
    for(int i=1;i<=Q;i++){int opt=read(),u=read();if(opt==1) Que[++cnt].fi=u,Que[cnt].se=ps;else E[u].tim=ps=i;}sort(E+1,E+M+1,cmp);
    for(int i=1;i<=M;i++){
        int u=E[i].u,v=E[i].v,tim=E[i].tim;
        if(U.find(u)==U.find(v)) continue;
        u=U.find(u),v=U.find(v);
        //cerr<<"u:"<<u<<" v:"<<v<<" tim:"<<tim<<endl;
        ++tot;U.f[u]=U.f[v]=tot;T[tot]=tim;
        vec[tot].pb(u),vec[tot].pb(v);
    }memset(dfn,127/3,sizeof(dfn));dfn[0]=0;
    for(int i=1;i<=tot;i++) if(U.find(i)==i) dfs(i,0);
    for(int i=1;i<=N;i++) S.Modify(1,1,N,dfn[i],Val[i]);
    //return 0;
    //for(int i=1;i<=2*N-1;i++) printf("%d ",dfn[i]);printf("\n");
    for(int i=1;i<=cnt;i++){
        int u=Que[i].fi,tim=Que[i].se+1;
        int G=Qmax(u,tim),L=dfn[G],R=dfn[G]+siz[G]-1,WW;
        //return 0;
        printf("%d\n",WW=S.Query(1,1,N,L,R));
        //return 0;
        if(!WW) continue;
        S.Modify(1,1,N,dfn[MM[WW]],0);
    }return 0;
}

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N=6e5+5;
#define ls now<<1
#define rs now<<1|1
#define F first
#define S second
int Head[N],vet[N<<1],Next[N<<1];
int E[N][2],que[N<<2][3],bl[N],sz[N],FA[N],p[N],tree[N<<2],loc[N<<2],vis[N],val[N],fa[N][20];
pair<int,int> ran[N];
vector<int> vec[N];
int n,m,q,edgenum,nodenum,ans,LOC,cnt,now;
int find(int u){ return FA[u]==u?u:FA[u]=find(FA[u]); }
inline void addedge(int u, int v){
	edgenum++;
	vet[edgenum]=v;
	Next[edgenum]=Head[u];
	Head[u]=edgenum;
}
void update(int now, int l, int r, int x, int y){
	if (l==r){ tree[now]=y; loc[now]=x; return; }
	int mid=(l+r)>>1;
	if (mid>=x) update(ls,l,mid,x,y);
	else update(rs,mid+1,r,x,y);
	tree[now]=max(tree[ls],tree[rs]);
	if (tree[ls]>tree[rs]) loc[now]=loc[ls];
	else loc[now]=loc[rs];
}
void query(int now, int l, int r, int x, int y){
	if (l==x && r==y){
		if (tree[now]>=ans) ans=tree[now],LOC=loc[now];
		return;
	}
	int mid=(l+r)>>1;
	if (mid>=y) query(ls,l,mid,x,y);
	else if (mid<x) query(rs,mid+1,r,x,y);
	else query(ls,l,mid,x,mid),query(rs,mid+1,r,mid+1,y);
}
void dfs(int u){
	vis[u]=1; bl[u]=cnt; sz[cnt]++;
	vec[cnt].push_back(u);
	for (int e=Head[u]; e; e=Next[e]){
		int v=vet[e];
		if (!vis[v]) dfs(v);
	}
}
void dfs1(int u, int f){
	fa[u][0]=f; ran[u]=make_pair(1e9,0);
	for (int i=1; i<=19; i++) fa[u][i]=fa[fa[u][i-1]][i-1];
	if (val[u]==-1){
		ran[u]=make_pair(now+1,now+sz[u]);
		for (int i=0; i<sz[u]; i++) update(1,1,n,now+i+1,p[vec[u][i]]);
		now+=sz[u]; return;
	}
	for (int e=Head[u]; e; e=Next[e]){
		int v=vet[e];
		dfs1(v,u);
		ran[u].F=min(ran[u].F,ran[v].F);
		ran[u].S=max(ran[u].S,ran[v].S);
	}
}
inline int read(){
	int num=0; char ch=getchar();
	while (ch<'0' || ch>'9') ch=getchar();
	while (ch>='0' && ch<='9') num=(num<<3)+(num<<1)+ch-'0',ch=getchar();
	return num;
}
void print(int x){
	if (!x) return;
	print(x/10); putchar(x%10+'0');
}
int main(){
//	freopen("D.in","r",stdin);
//	freopen("D.out","w",stdout);
	n=read(),m=read(),q=read();
	for (int i=1; i<=n; i++) p[i]=read();
	for (int i=1; i<=m; i++) E[i][0]=read(),E[i][1]=read();
	for (int i=1; i<=q; i++){
		que[i][0]=read(),que[i][1]=read();
		if (que[i][0]==2) vis[que[i][1]]=1,que[i][2]=i;
	}
	for (int i=1; i<=m; i++)
		if (!vis[i]) addedge(E[i][0],E[i][1]),addedge(E[i][1],E[i][0]);
	memset(vis,0,sizeof(vis));
	for (int i=1; i<=n; i++)
		if (!vis[i]) cnt++,dfs(i),FA[cnt]=cnt,val[cnt]=-1;
	memset(Head,0,sizeof(Head)); edgenum=0; nodenum=cnt;
	for (int i=q; i>=1; i--){
		if (que[i][0]==1) continue;
		int u=bl[E[que[i][1]][0]],v=bl[E[que[i][1]][1]];
		u=find(u),v=find(v);
		if (u!=v){
			nodenum++; val[nodenum]=que[i][2];
			FA[nodenum]=FA[u]=FA[v]=nodenum;
			addedge(nodenum,u); addedge(nodenum,v);
		}
	}
	for (int i=nodenum; i>=1; i--)
		if (ran[i]==make_pair(0,0)) dfs1(i,0);
	for (int i=1; i<=q; i++){
		if (que[i][0]==2) continue;
		int u=bl[que[i][1]];
		for (int j=19; ~j; j--)
			if (val[fa[u][j]]>i) u=fa[u][j];
		ans=LOC=-1; query(1,1,n,ran[u].F,ran[u].S);
		if (!ans) puts("0");
		else print(ans),puts("");
		update(1,1,n,LOC,0);
	}
	return 0;
}
/*
5 4 6
1 2 5 4 3
1 2
2 3
1 3
4 5
1 1
2 1
2 3
1 1
1 2
1 2
*/

#include<bits/stdc++.h>

#define pb push_back
#define eb emplace_back
#define mp make_pair
#define fi first
#define se second
#define all(x) (x).begin(), (x).end()
#define debug(x) cerr << #x << " = " << x << endl;

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int MAXN = (int)5e5 + 5;
const int MAXM = (int)3e5 + 5;
const int MAXQ = (int)5e5 + 5;

pii e[MAXM], que[MAXQ], t[MAXN << 2];
vector<int> adj[MAXN];
int tin[MAXN], tout[MAXN], timer;
int par[MAXN], arr[MAXN];
bool del[MAXM];
int n, m, q;

int getPar(int x) {
  if (x == par[x]) {
    return x;
  }

  return par[x] = getPar(par[x]);
}

void uni(int a, int b) {
  a = getPar(a);
  b = getPar(b);

  if (a == b) {
    return;
  }

  ++n;
  par[n] = n;
  par[a] = n;
  par[b] = n;
  adj[n].pb(a);
  adj[n].pb(b);
}

void dfs(int v) {
  tin[v] = ++timer;

  for (int to : adj[v]) {
    dfs(to);
  }

  tout[v] = timer;
}

pii segMax(int v, int tl, int tr, int l, int r) {
  if (l > r || tl > r || tr < l) {
    return mp(0, 0);
  }

  if (l <= tl && tr <= r) {
    return t[v];
  }

  int mid = (tl + tr) >> 1;
  int c1 = (v << 1), c2 = (c1 | 1);

  return max(segMax(c1, tl, mid, l, r), segMax(c2, mid + 1, tr, l, r));
}

void updPos(int v, int tl, int tr, int p, pii x) {
  if (tl == tr) {
    t[v] = x;
    return;
  }

  int mid = (tl + tr) >> 1;
  int c1 = (v << 1), c2 = (c1 | 1);

  if (p <= mid) {
    updPos(c1, tl, mid, p, x);
  }
  else {
    updPos(c2, mid + 1, tr, p, x);
  }

  t[v] = max(t[c1], t[c2]);
}

void solve() {
  scanf("%d %d %d", &n, &m, &q);

  for (int i = 1; i <= n; ++i) {
    scanf("%d", &arr[i]);
  }

  for (int i = 1; i <= m; ++i) {
    int u, v;
    scanf("%d %d", &u, &v);
    e[i] = mp(u, v);
  }

  for (int i = 1; i <= q; ++i) {
    int a, b;
    scanf("%d %d", &a, &b);
    que[i] = mp(a, b);

    if (a == 2) {
      del[b] = 1;
    }
  }

  for (int i = 1; i <= n; ++i) {
    par[i] = i;
  }

  for (int i = 1; i <= m; ++i) {
    if (!del[i]) {
      uni(e[i].fi, e[i].se);
    }
  }

  for (int i = q; i > 0; --i) {
    int tp = que[i].fi;

    if (tp == 2) {
      int id = que[i].se;
      uni(e[id].fi, e[id].se);
    }
    else {
      que[i].se = getPar(que[i].se);
    }
  }

  for (int i = 1; i <= n; ++i) {
    if (getPar(i) == i) {
      dfs(i);
    }
  }

  for (int i = 1; i <= n; ++i) {
    updPos(1, 1, n, tin[i], mp(arr[i], tin[i]));
  }

  for (int i = 1; i <= q; ++i) {
    int tp = que[i].fi;

    if (tp == 1) {
      int v = que[i].se;
      pii tmp = segMax(1, 1, n, tin[v], tout[v]);

      if (tmp.fi == 0) {
        printf("0\n");
      }
      else {
        printf("%d\n", tmp.fi);
        updPos(1, 1, n, tmp.se, mp(0, 0));
      }
    }
  }
}

int main() {
  int tt = 1;

  while (tt--) {
    solve();
  }

  return 0;
}

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=4e5+9,M=5e6+9,QQ=5e6+9;
#define ls (x<<1)
#define rs (x<<1|1)
#define mp make_pair
#define PII pair<int,int>
struct Tree
{
	pair<int,int> val;
} tr[N<<2];
struct Query
{
	int v,op;
} Q[QQ];
struct Eage
{
	int x,y;
} e[M];
int n,m,q,a[N],dep[N];
int fa[N],siz[N],dfn[N],ind;
vector<int> G[N];
bool vis[M];

int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}

void dfs(int u)
{
	dfn[u]=++ind;
	siz[u]=1;
	for(auto v:G[u]) dfs(v),siz[u]+=siz[v];
}

void change(int x,int l,int r,int pos,PII v)
{
	if(l==r) {tr[x].val=v;return;}
	int mid=(l+r)>>1;
	if(pos<=mid) change(ls,l,mid,pos,v);
	else change(rs,mid+1,r,pos,v);
	tr[x].val=max(tr[ls].val,tr[rs].val);
}

PII query(int x,int l,int r,int L,int R)
{
	if(L<=l&&r<=R) return tr[x].val;
	int mid=(l+r)>>1;
	PII res=mp(0,0);
	if(L<=mid) res=max(res,query(ls,l,mid,L,R));
	if(R>mid) res=max(res,query(rs,mid+1,r,L,R));
	return res;
}

inline void Merge(int x,int y)
{
	int fx=find(x),fy=find(y);
	if(fx==fy) return;
	// if(dep[fx]>dep[fy]) swap(fx,fy);
	fa[fx]=fa[fy]=++n;
	fa[n]=n;
	G[n].push_back(fx);
	G[n].push_back(fy);
	// if(dep[fx]==dep[fy]) dep[fy]++;
}

int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),fa[i]=i,dep[i]=1;
	for(int i=1;i<=m;i++) scanf("%d%d",&e[i].x,&e[i].y);
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&Q[i].op,&Q[i].v);
		if(Q[i].op==2) vis[Q[i].v]=true;
	}
	for(int i=1;i<=m;i++)
		if(!vis[i]) Merge(e[i].x,e[i].y);
	for(int i=q;i>=1;i--)
	{
		if(Q[i].op==1) Q[i].v=find(Q[i].v);
		else
			Merge(e[Q[i].v].x,e[Q[i].v].y);
	}
	int last=0;
	for(int i=1;i<=n;i++)
		if(find(i)==i)
		{
			if(last) Merge(last,i),last=i;
			else last=i;
		}
	dfs(last);
	for(int i=1;i<=n;i++)
		change(1,1,n,dfn[i],mp(a[i],dfn[i]));
	for(int i=1;i<=q;i++)
		if(Q[i].op==1)
		{
			PII ans=query(1,1,n,dfn[Q[i].v],dfn[Q[i].v]+siz[Q[i].v]-1);
			printf("%d\n",ans.first);
			change(1,1,n,ans.second,mp(0,0));
		}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define fst first
#define snd second
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define for_tests(t, tt) int t; scanf("%d", &t); for(int tt = 1; tt <= t; tt++)
#ifndef ONLINE_JUDGE
#define debug(args...) fprintf(stderr,args)
#else
#define debug(args...)
#endif //ONLINE_JUDGE
template<typename T> inline T abs(T t) { return t < 0? -t : t; }
const ll modn = 1000000007;
inline ll mod(ll x) { return x % modn; }
#define IOS() ios::sync_with_stdio(0),cin.tie(0)

const int MAXN = 500005;

int n, m, k;
int s[MAXN];

bool apg[MAXN];

vector<pii> adj[MAXN];
vector<int> comp[MAXN];
int p[MAXN], sz[MAXN];

int raiz(int u){
    if(p[u] == u) return u;
    return p[u] = raiz(p[u]);
}

int join(int u, int v){
    u = raiz(u);
    v = raiz(v);
    if(u == v) return 0;

    if(sz[u] < sz[v])
        swap(u, v);

    sz[u] += sz[v];
    p[v] = u;
    for(int x: comp[v])
        comp[u].pb(x);
    return v;
}
vector<pii> qry;
vector<pii> ares(1);
set<pii> rcomp[MAXN];
int main (){
    int q;
	scanf("%d%d%d", &n, &m, &q);
	for(int a=1;a<=n;a++){
        scanf("%d", s+a);
        p[a] = a;
        sz[a] = 1;
        comp[a].pb(a);
	}
    for(int a=1;a<=m;a++){
        int i, j;
        scanf("%d%d", &i, &j);
        adj[i].pb({j, a});
        adj[j].pb({i, a});
        ares.pb({i, j});
    }
    vector<int> mnRaiz(q);
    vector<vector<int>> mnComp(q);
    for(int a=0;a<q;a++){
        int t, i;
        scanf("%d %d", &t, &i);
        if(t == 2)
            apg[i] = 1;
        qry.pb({t, i});
    }
    for(int a=1;a<=m;a++){
        if(apg[a]) continue;
        int v = join(ares[a].fst, ares[a].snd);
        comp[v].clear();
    }

    for(int a=q-1;a>=0;a--){
        int t,i;
        t = qry[a].fst;
        i = qry[a].snd;
        if(t == 1)
            continue;
        int u = ares[i].fst, v = ares[i].snd;
        mnRaiz[a] = join(u, v);
        if(mnRaiz[a] > 0){
            mnComp[a] = comp[mnRaiz[a]];
            comp[mnRaiz[a]].clear();
        }
    }

    for(int u=1;u<=n;u++){
        if(u == p[u]){
            for(int v: comp[u]){
                rcomp[u].insert({-s[v], v});
            }
        }
    }
    for(int a=0;a<q;a++){
        int t,i;
        t = qry[a].fst;
        i = qry[a].snd;

        if(t == 1){
            int r = raiz(i);
            pii mai = {0, 0};
            if(!rcomp[r].empty()){
                mai = *rcomp[r].begin();
                rcomp[r].erase(rcomp[r].begin());
            }
            printf("%d\n", -mai.fst);
        }
        else{
            if(mnRaiz[a] == 0) continue;
            int mn = mnRaiz[a];
            int oldR = raiz(mn);
            assert(oldR != mn);
            p[mn] = mn;
            for(int v: mnComp[a]){
                p[v] = mn;
                if(rcomp[oldR].find({-s[v], v}) != rcomp[oldR].end()){
                    rcomp[oldR].erase({-s[v], v});
                    rcomp[mn].insert({-s[v], v});
                }
            }
        }
    }
}

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 10;

int n, m, q;
int p[N];
int wei[N], w[N];
int tim[N], seq[N];
struct edge{
    int l, r;
}e[N];

struct query{
    int l, r, id;
}qq[N];
int tot;
int find(int x)
{
    if(x == p[x]) return x;
    return p[x] = find(p[x]);
}

int cmp(int a, int b)
{
    return tim[a] > tim[b];
}
int ans[N];
vector<int>g[N];

int in[N],out[N], num, pre[N], f[N][21];
int tr[N << 2];

void dfs(int u)
{
    in[u] = ++ num;
    pre[num] = u;
    for (int j = 1; j <= 20; j ++)
        f[u][j] = f[f[u][j - 1]][j - 1];
    for (auto &j : g[u])
    {
        f[j][0] = u;
        dfs(j);
    }
    out[u] = num;
}

void pushup(int rt)
{
    if(w[tr[rt << 1]] >= w[tr[rt << 1 | 1]])
    {
        tr[rt] = tr[rt << 1];
    }
    else
        tr[rt] = tr[rt << 1 | 1];
}

int get(int x, int t)
{
    for (int i = 20; i >= 0; i --)
        if(f[x][i] && wei[f[x][i]] >= t)
            x = f[x][i];
    return x;
}

void build(int rt, int l, int r)
{
    if(l == r)
    {
        tr[rt] = pre[l];
        return ;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    pushup(rt);
}

int query(int rt, int L, int R, int l, int r)
{
    if(L <= l && R >= r)
    {
        return tr[rt];
    }
    int mid = l + r >> 1;
    int res = 0, res1 = 0, res2 = 0;
    if(L <= mid) res1 = query(rt << 1, L, R, l, mid);
    if(R > mid) res2 = query(rt << 1 | 1, L, R, mid + 1, r);
    if(w[res1] >= w[res2])
        res = res1;
    else
        res = res2;
    return res;
}

void update(int rt, int L, int C, int l, int r)
{
    if(l == r)
    {
        w[pre[l]] = C;
        tr[rt] = pre[l];
        return ;
    }
    int mid = l + r >> 1;
    if(L <= mid) update(rt << 1, L, C, l, mid);
    else update(rt << 1 | 1, L, C, mid + 1, r);
    pushup(rt);
}

int main()
{
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 1; i <= n; i ++) scanf("%d", &w[i]), wei[i] = q + 1;
    for (int i = 1; i <= n + n + 10; i ++) p[i] = i;
    for (int i = 1; i <= m; i ++)
    {
        scanf("%d%d", &e[i].l, &e[i].r);
        tim[i] = q + 1;
        seq[i] = i;
    }
    for (int i = 1; i <= q; i ++)
    {
        scanf("%d%d", &qq[i].l, &qq[i].r);
        qq[i].id = i;
        if(qq[i].l == 2)
            tim[qq[i].r] = i;
    }
    sort(seq + 1, seq + m + 1, cmp);
    tot = n;
    for (int i = 1; i <= m; i ++)
    {
        int u = e[seq[i]].l, v = e[seq[i]].r, t = tim[seq[i]];
        int fx = find(u), fy = find(v);
        if(fx == fy) continue;
        wei[++ tot] = t;
        g[tot].push_back(fx); g[tot].push_back(fy);
        p[fx] = tot, p[fy] = tot;
    }
    for (int i = tot; i >= 1; i --)
        if(!in[i])
            dfs(i);
    build(1, 1, num);
    for (int i = 1; i <= q; i ++)
    {
        if(qq[i].l == 1)
        {
            int v = get(qq[i].r, i);
            int tmp = query(1, in[v], out[v], 1, num);
        //   cout << tmp << '\n';
            ans[i] = w[tmp];
            if(ans[i])
                update(1, in[tmp], 0, 1, num);
            printf("%d\n", ans[i]);
        }
    }

}

#include <bits/stdc++.h>

#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define eb emplace_back
#define ar array

using namespace std;
typedef long long ll;
typedef pair<int, int> ii;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const int maxn = 5e5 + 5;

int U[maxn], V[maxn], type[maxn], id[maxn];
int tin[maxn], tout[maxn], par[maxn], a[maxn], root[maxn];
int N, M, Q;
bool del[maxn];
vector<int> adj[maxn];
ii tr[4 * maxn];

int finds(int u) {
  if (par[u] == u) return u;
  return par[u] = finds(par[u]);
}

void merges(int u, int v) {
  u = finds(u); v = finds(v);
  if (u == v) return;
  ++N;
  par[N] = N;
  par[u] = N;
  par[v] = N;
  adj[N].eb(u); adj[N].eb(v);
}

#define lc id << 1
#define rc id << 1 | 1
void upd(int pos, ii v, int id = 1, int l = 1, int r = N) {
  if (l == r) {
    tr[id] = v;
    return;
  }
  int mid = (l + r) / 2;
  if (pos <= mid) upd(pos, v, lc, l, mid);
  else upd(pos, v, rc, mid + 1, r);
  tr[id] = max(tr[lc], tr[rc]);
}

ii query(int L, int R, int id = 1, int l = 1, int r = N) {
  if (R < l || r < L)
    return mp(0, 0);
  if (L <= l && r <= R)
    return tr[id];
  int mid = (l + r) / 2;
  return max(query(L, R, lc, l, mid), query(L, R, rc, mid + 1, r));
}

void dfs(int u) {
  static int nTime = 0;
  tin[u] = ++nTime;
  for (int v : adj[u]) {
    dfs(v);
  }
  tout[u] = nTime;
}

signed main(void) {
  ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  #ifdef LOCAL
    freopen("A.INP", "r", stdin);
    freopen("A.OUT", "w", stdout);
  #endif // LOCAL

  cin >> N >> M >> Q;
  iota(par + 1, par + 1 + N, 1);
  for (int i = 1; i <= N; ++i) {
    cin >> a[i];
  }
  for (int i = 1; i <= M; ++i) {
    cin >> U[i] >> V[i];
  }
  for (int i = 1; i <= Q; ++i) {
    cin >> type[i] >> id[i];
    if (type[i] == 2) {
      del[id[i]] = true;
    }
  }

  for (int i = 1; i <= M; ++i) {
    if (!del[i]) {
      merges(U[i], V[i]);
    }
  }

  for (int i = Q; i >= 1; --i) {
    if (type[i] == 1) {
      root[i] = finds(id[i]);
    } else {
      merges(U[id[i]], V[id[i]]);
    }
  }

  for (int i = 1; i <= N; ++i) {
    if (finds(i) == i) {
      dfs(i);
    }
  }

  for (int i = 1; i <= N; ++i) {
    upd(tin[i], mp(a[i], i));
  }

  for (int i = 1; i <= Q; ++i) {
    if (type[i] == 1) {
      ii res = query(tin[root[i]], tout[root[i]]);
      cout << res.fi << '\n';
      upd(tin[res.se], mp(0, res.se));
    }
  }
}

#include<bits/stdc++.h>
#define ll long long
#define mid ((l+r)/2)
using namespace std;
int n, m, q;

int A[1000009],B[1000009];
vector<int> adj[1000009];
int arr[1000009],l[1000009],r[1000009],per[1000009],p[1000009], No[1000009],cor[1000009];
int P(int x){
    if(p[x] == x) return x;
    p[x] = P(p[x]);
    return p[x];

}
int c = 0;
void dfs(int x){
    if(x <= n) {arr[++c] = per[x], l[x] = c, r[x] = c;
    return;
    }
    l[x] = n, r[x] = 1;
    for(int y : adj[x]){
        dfs(y);
        l[x] = min(l[x], l[y]);
        r[x] = max(r[x], r[y]);

    }

}
set<pair<int,int> > S;
void rem(int x){
    S.erase(S.find({l[x], r[x]}));
    for(int y : adj[x]){
        S.insert({l[y], r[y]});
    }
}
struct node{
    int mx;
    node *L, *R;
    void upd(){
        this->mx = max(this->L->mx, this->R->mx);
    }
};
void build(node *&x, int l, int r){
    x = new node();
    if(l==r) {x->mx = arr[l]; return;}
    build(x->L,l,mid);
    build(x->R,mid+1,r);
    x->upd();
}
void upd(node *&x, int l, int r, int p){
    if(p < l || p > r) return;
    if(l == r){
        x ->mx = 0;
        return;
    }
    upd(x->L,l,mid,p);
    upd(x->R,mid+1,r,p);
    x->upd();
}
int cnt(node *&x, int l, int r, int a, int b){
    if(l > b || r  < a) return 0;
    if(l >= a && r <= b) return x->mx;
    return max(cnt(x->L,l,mid,a,b),
               cnt(x->R,mid+1,r,a,b));

}
main(){
    scanf("%d %d %d", &n, &m, &q);
    for(int i = 1; i <= n; i++){
        scanf("%d", &per[i]);
        cor[per[i]] = i;
    }
    for(int i = 1; i <= m; i++){
         scanf("%d %d", &A[i], &B[i]);
    }
    int Z = m;
    vector<pair<int,int> > Q;
    for(int i = 1; i <= q; i++){
        int t;
        scanf("%d", &t);
        if(t == 1){
            int v;

            scanf("%d", &v);
            Q.push_back({v, Z});
        }
        else {
            int i;

            scanf("%d", &i);
            No[i] = Z;
            Z--;
        }
    }
    vector<pair<int,int> > O;
    for(int i = 1; i <= m; i++){
        O.push_back({No[i],i});
    }
    sort(O.begin(), O.end());
    for(int i = 1; i <= n+m+1; i++){
        p[i] = i;

    }
    for(int i = 0; i < m; i++){
        int x = O[i].second;
        int u = P(A[x]), v = P(B[x]);
        if(u == v) continue;
        p[u] = n + i + 1, p[v] = n + i + 1;
        adj[n+i+1].push_back(u);
        adj[n+i+1].push_back(v);
    }
     adj[n+m+1].push_back(P(1));
    for(int i = 1; i < n; i++){

        int u = P(i), v = P(i+1);
        if(u == v) continue;
        p[u] = n+m+1, p[v] = n+m+1;
        adj[n+m+1].push_back(v);
    }
    dfs(n+m+1);
    S.insert({1,n});
    int mx = n + m + 1;
    node *rt;
    build(rt, 1, n);
    for(int i = 0; i < Q.size(); i++){
        int v = Q[i].first, z = Q[i].second;
        while(mx > n + z){
            if(!l[mx]) {mx--; continue;}
            rem(mx);
            mx--;

        }

        auto it = S.lower_bound({l[v]+1, -1});
        it--;
        int L = it->first, R = it->second;
        int u = cnt(rt, 1, n, L, R);
        printf("%d\n", u);
        int ind = l[cor[u]];
        upd(rt,1,n, ind);

    }

}/*

5 5 5
1 2 3 4 5
1 2
2 3
3 4
4 5
5 1
1 1
2 1
2 2
1 5
1 1*/

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<ctime>
#include<climits>
#define ll long long
#define MAXN 200005
#define MAXM 300005
#define MAXQ 500004
using namespace std;
inline ll read(){
	ll x=0,f=1;char s=getchar();
	while((s<'0'||s>'9')&&s>0){if(s=='-')f*=-1;s=getchar();}
	while(s>='0'&&s<='9'){x=(x<<1)+(x<<3)+s-'0';s=getchar();}
	return f>0?x:-x;
}
int n=read(),m=read(),q=read(),w[MAXN],q1,q2,u[MAXM],v[MAXM];
int c[MAXQ],gp[MAXQ];
bool del[MAXM],st[MAXQ];
int f[MAXN*3],p,IN=n,IM,ls[MAXN<<1],rs[MAXN<<1],ld[MAXN<<1],rd[MAXN<<1],tp[MAXN],fa[MAXN];
inline int findset(int x){return fa[x]==0?x:(fa[x]=findset(fa[x]));}
inline int MAX(int x,int y){return w[x]>w[y]?x:y;}
inline void dfs(int x){
	if(x==0)return;
	ld[x]=IM,dfs(ls[x]),dfs(rs[x]);
	if(x<=n)IM++,f[p+IM]=x;
	rd[x]=IM;
}
inline int zero(int x){
	int res=w[x];
	for(w[x]=0,x=p+rd[x]>>1;x>0;x>>=1)f[x]=MAX(f[x<<1],f[x<<1|1]);
	return res;
}
inline int sch(int l,int r){
	int res=0;
	for(l=p+l-1,r=p+r+1;(l^1)!=r;l>>=1,r>>=1){
		if((l&1)^1)res=MAX(f[l^1],res);
		if(r&1)res=MAX(f[r^1],res);
	}
	return res;
}
int main()
{
	for(int i=1;i<=n;i++)w[i]=read(),tp[i]=i;
	for(int i=1;i<=m;i++)u[i]=read(),v[i]=read();
	for(int i=1;i<=q;i++){
		st[i]=read()-1,c[i]=read();
		if(st[i])del[c[i]]=1;
	}
	for(int i=1;i<=m;i++)
		if(!del[i])
			if(findset(u[i])!=findset(v[i])){
				IN++,ls[IN]=tp[findset(u[i])],rs[IN]=tp[findset(v[i])];
				fa[findset(v[i])]=findset(u[i]),tp[findset(u[i])]=IN;
			}
	for(int i=q;i>0;i--){
		if(st[i]){
			int x=u[c[i]],y=v[c[i]];
			if(findset(x)!=findset(y)){
				IN++,ls[IN]=tp[findset(x)],rs[IN]=tp[findset(y)];
				fa[findset(y)]=findset(x),tp[findset(x)]=IN;
			}
		}
		else gp[i]=tp[findset(c[i])];
	}
	for(p=1;p<n+2;p<<=1);
	for(int i=IN;i>0;i--)if(!rd[i])dfs(i);
	for(int i=p-1;i>0;i--)f[i]=MAX(f[i<<1],f[i<<1|1]);
	for(int i=1;i<=q;i++)
		if(!st[i])printf("%d\n",zero(sch(ld[gp[i]]+1,rd[gp[i]])));
	return 0;
}

#include <bits/stdc++.h>

int32_t main() {
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
#endif
    int32_t n, m, q;
    scanf("%d%d%d", &n, &m, &q);
    std::vector<int32_t> a(n);
    for (int32_t i = 0; i < n; i++)
        scanf("%d", &a[i]);
    std::vector<std::pair<int32_t, int32_t>> edges(m);
    for (int32_t i = 0; i < m; i++) {
        scanf("%d%d", &edges[i].first, &edges[i].second);
        --edges[i].first;
        --edges[i].second;
    }
    std::vector<bool> removed(m);
    std::vector<std::pair<int32_t, int32_t>> queries(q);
    for (int32_t i = 0; i < q; i++) {
        scanf("%d%d", &queries[i].first, &queries[i].second);
        --queries[i].second;
        if (queries[i].first == 2)
            removed[queries[i].second] = true;
    }
    std::vector<int32_t> parent(n, -1);
    auto find = [&](int32_t x) {
        while (0 <= parent[x]) x = parent[x];
        return x;
    };
    std::vector<std::vector<int32_t>> adj(n);
    auto merge = [&](int32_t u, int32_t v) {
        u = find(u), v = find(v);
        if (u == v) return;
        if (parent[u] < parent[v])
            std::swap(u, v);
        parent[v] += parent[u];
        adj[v].push_back(u);
        parent[u] = v;
    };
    for (int32_t i = 0; i < m; i++) {
        if (removed[i]) continue;
        merge(edges[i].first, edges[i].second);
    }
    std::vector<int32_t> children;
    for (int32_t i = q; i --> 0;) {
        if (queries[i].first == 1) {
            int32_t x = find(queries[i].second);
            queries[i].second = x;
            children.push_back(adj[x].empty() ? -1 : adj[x].back());
        } else {
            auto edge = edges[queries[i].second];
            merge(edge.first, edge.second);
        }
    }
    std::reverse(children.begin(), children.end());
    std::vector<std::pair<int32_t, int32_t>> tree;
    tree.reserve(n + n);
    tree.resize(n);
    int32_t stamp = 0;
    std::vector<int32_t> left(n), right(n);
    std::function<void(int32_t)> euler = [&](int32_t u) {
        tree.emplace_back(a[u], stamp);
        left[u] = stamp++;
        for (int32_t v : adj[u])
            euler(v);
        right[u] = stamp;
    };
    for (int32_t i = 0; i < n; i++) {
        if (find(i) == i) euler(i);
    }
    for (int32_t i = n; i --> 1;)
        tree[i] = std::max(tree[i + i], tree[i + i + 1]);
    for (int32_t i = 0, j = 0; i < q; i++) {
        if (queries[i].first == 2) continue;
        int32_t l = left[queries[i].second];
        int32_t r = children[j++];
        r = (r < 0 ? l + 1 : right[r]);
        std::pair<int32_t, int32_t> res;
        for (l += n, r += n; l < r; l /= 2, r /= 2) {
            if (l & 1) res = std::max(res, tree[l++]);
            if (r & 1) res = std::max(tree[--r], res);
        }
        printf("%d\n", res.first);
        int32_t x = res.second + n;
        tree[x].first = 0;
        while (x /= 2)
            tree[x] = std::max(tree[x + x], tree[x + x + 1]);
    }
    return 0;
}

#include <algorithm>
#include <cstdio>
using namespace std;
int const maxn = 400003;
int n = 0, m = 0, q = 0, cPoint = 0;
int p[maxn];
struct Edge {
	int u, e;
	int id;
};
Edge E[maxn];
int deleteTime[maxn];
inline bool operator<(Edge const &lhs, Edge const &rhs) { return deleteTime[lhs.id] > deleteTime[rhs.id]; }

int opt[500003], Sec[500003];

int head[maxn], nxt[maxn], to[maxn], cnt = 0;
inline void insert(int u, int e) {
	nxt[++cnt] = head[u];
	head[u] = cnt;
	to[cnt] = e;
}

int fath[maxn];
inline int find(int x) { return fath[x] == x ? x : fath[x] = find(fath[x]); }
int ti[maxn];
void CreateTheTree() {
	std::sort(E + 1, E + m + 1);
	for (int i = 1; i <= 2 * n; ++i)
		fath[i] = i;
	cPoint = n;
	for (int i = 1; i <= m; ++i) {
		if (find(E[i].u) == find(E[i].e)) continue;
		++cPoint;
		ti[cPoint] = deleteTime[E[i].id];
		insert(cPoint, find(E[i].u));
		insert(cPoint, find(E[i].e));
		fath[find(E[i].u)] = cPoint;
		fath[find(E[i].e)] = cPoint;
	}
}

int fa[20][maxn], Ldfn[maxn], Rdfn[maxn];
int dfn[maxn], idfn[maxn];
void dfs(int x, int f) {
	fa[0][x] = f;
	for (int j = 1; j <= 18; ++j)
		fa[j][x] = fa[j - 1][fa[j - 1][x]];
	if (x <= n) {
		Ldfn[x] = Rdfn[x] = dfn[x] = ++dfn[0];
		idfn[dfn[x]] = x;
		return;
	}
	Ldfn[x] = cPoint + 1, Rdfn[x] = 0;
	for (int i = head[x]; i; i = nxt[i]) {
		dfs(to[i], x);
		Ldfn[x] = std::min(Ldfn[x], Ldfn[to[i]]);
		Rdfn[x] = std::max(Rdfn[x], Rdfn[to[i]]);
	}
}

struct MX {
	int v, pos;
};
MX operator|(MX const &lhs, MX const &rhs) { return lhs.v > rhs.v ? lhs : rhs; }
MX mx[maxn << 2];
void CreateSeg(int po, int L, int R) {
	if (L == R) {
		mx[po].v = p[idfn[L]];
		mx[po].pos = idfn[L];
		return;
	}
	int mid = (L + R) >> 1;
	CreateSeg(po << 1, L, mid);
	CreateSeg(po << 1 | 1, mid + 1, R);
	mx[po] = mx[po << 1] | mx[po << 1 | 1];
}
void Modify(int po, int L, int R, int x) {
	if (L == R) {
		mx[po].v = p[idfn[L]];
		return;
	}
	int mid = (L + R) >> 1;
	if (x <= mid)
		Modify(po << 1, L, mid, x);
	else
		Modify(po << 1 | 1, mid + 1, R, x);
	mx[po] = mx[po << 1] | mx[po << 1 | 1];
}
MX query(int po, int L, int R, int l, int r) {
	if (l <= L && R <= r)
		return mx[po];
	int mid = (L + R) >> 1;
	if (r <= mid)
		return query(po << 1, L, mid, l, r);
	else if (l > mid)
		return query(po << 1 | 1, mid + 1, R, l, r);
	else
		return query(po << 1, L, mid, l, r) | query(po << 1 | 1, mid + 1, R, l, r);
}

int jump(int x, int time) {
	for (int j = 18; ~j; --j)
		if (ti[fa[j][x]] > time)
			x = fa[j][x];
	return x;
}
int main() {
	scanf("%d %d %d", &n, &m, &q);
	for (int i = 1; i <= n; ++i)
		scanf("%d", p + i);
	for (int i = 1; i <= m; ++i) {
		scanf("%d %d", &E[i].u, &E[i].e);
		E[i].id = i;
		deleteTime[i] = q + 1;
	}
	for (int i = 1; i <= q; ++i) {
		scanf("%d %d", opt + i, Sec + i);
		if (opt[i] == 2) deleteTime[Sec[i]] = i;
	}
	CreateTheTree();
	for (int i = 1; i <= cPoint; ++i)
		if (fath[i] == i) dfs(i, 0);
	CreateSeg(1, 1, n);

	for (int i = 1; i <= q; ++i)
		if (opt[i] == 1) {
			int x = jump(Sec[i], i);
			MX res = query(1, 1, n, Ldfn[x], Rdfn[x]);
			printf("%d\n", res.v);
			if (res.v != 0) {
				p[res.pos] = 0;
				Modify(1, 1, n, dfn[res.pos]);
			}
		}
	return 0;
}

#include<bits/stdc++.h>
#define N 400010
#define M 300010
#define Q 500010
#define D 25
using namespace std;
template<typename T> void read(T &X){
	X=0;char C=getchar();T Sig=1;
	for (;!isdigit(C);C=getchar()) if (C=='-') Sig=-1;
	for (; isdigit(C);C=getchar()) X=(X<<3)+(X<<1)+C-'0';
	X*=Sig;
}
template<typename T> void write(T x){
	if (x<0){putchar('-');x=-x;}
	T y=0;int wei=0;
	while (x>9){y=y*10+x%10;x/=10;++wei;}putchar(x+48);
	while (wei--){putchar(y%10+48);y/=10;}
}
int n,m,q;
int w[N+M];
int pos[N+M];
struct rec{
	int u,v;
	bool flag;
	void rd(){
		read(u);
		read(v);
		flag=true;
		return;
	}
};
rec r[M];
struct ques{
	int op,x;
	void rd(){
		read(op);
		read(x);
		return;
	}
};
ques que[Q];
void get_data(){
	read(n);read(m);read(q);
	for (int i=1;i<=n;i++) read(w[i]);
	for (int i=1;i<=m;i++) r[i].rd();
	for (int i=1;i<=q;i++) que[i].rd();
	return;
}
int f[N+M];
int what[N+M];
int cnt;
int par(int x){
	while (x^f[x]) x=f[x]=f[f[x]];
	return x;
}
void merge(int x,int y){
	f[par(x)]=par(y);
	return;
}
struct side{
	int v,last;
	void get(int x,int y){
		v=x;last=y;
		return;
	}
};
int len;
side c[N+M];
int head[N+M];
int pt[N+M];
int fa[N+M][D];
int h[N+M];
bool vis[N+M];
int tmp;
int lst[N+M];
int lef[N+M];
int rig[N+M];
void put(int x,int y){
	c[++len].get(y,head[x]);
	head[x]=len;
	return;
}
void dfs(int p){
	lst[++tmp]=p;
	lef[p]=tmp;
	vis[p]=true;
	for (int i=head[p];i;i=c[i].last)
		if (!vis[c[i].v]){
			fa[c[i].v][0]=p;
			for (int j=1;fa[c[i].v][j-1];j++,h[c[i].v]++)
				fa[c[i].v][j]=fa[fa[c[i].v][j-1]][j-1];
			dfs(c[i].v);
		}
	rig[p]=tmp;
	return;
}
void prepare(){
	for (int i=1;i<=q;i++)
		if (que[i].op==2) r[que[i].x].flag=false;
	for (int i=1;i<=n;i++) f[i]=i;
	for (int i=1;i<=m;i++)
		if (r[i].flag) merge(r[i].u,r[i].v);
	cnt=n;
	for (int i=1;i<=n;i++){
		if (!what[par(i)]){
			what[par(i)]=++cnt;
			pt[cnt]=q+1;
			f[cnt]=cnt;
		}
		put(what[par(i)],i);
	}
	for (int i=1;i<=n;i++)
		if (f[i]==i) merge(i,what[i]);
	for (int i=q;i;i--)
		if (que[i].op==2){
			int u=par(r[que[i].x].u),v=par(r[que[i].x].v);
			if (u!=v){
				pt[++cnt]=i;
				f[cnt]=cnt;
				put(cnt,u);
				put(cnt,v);
				merge(u,cnt);
				merge(v,cnt);
			}
		}
	for (int i=1;i<=cnt;i++) h[i]=-1;
	for (int i=1;i<=cnt;i++) if (f[i]==i) dfs(i);
	for (int i=1;i<=n;i++) pos[w[i]]=i;
	return;
}
struct Segment_Tree{
	struct node{
		int lef,rig,v;
	};
	node tr[(N+M)<<2];
	void pushup(int i){
		tr[i].v=max(tr[i<<1].v,tr[i<<1|1].v);
		return;
	}
	void build(int i,int L,int R){
		tr[i].lef=L;
		tr[i].rig=R;
		if (L==R){
			tr[i].v=w[lst[L]];
			return;
		}
		int mid=(L+R)>>1;
		build(i<<1,L,mid);
		build(i<<1|1,mid+1,R);
		pushup(i);
		return;
	}
	void change(int i,int idx){
		if (tr[i].lef==tr[i].rig){
			tr[i].v=0;
			return;
		}
		if (idx<=tr[i<<1].rig) change(i<<1,idx);
		else change(i<<1|1,idx);
		pushup(i);
		return;
	}
	int query(int i,int L,int R){
		if (L<=tr[i].lef&&tr[i].rig<=R) return tr[i].v;
		int res=0;
		if (L<=tr[i<<1].rig) res=query(i<<1,L,R);
		if (R>=tr[i<<1|1].lef) res=max(res,query(i<<1|1,L,R));
		return res;
	}
};
Segment_Tree tree;
int jmp(int id,int x){
	for (int i=h[id];i>=0;i--)
		if (fa[id][i]&&pt[fa[id][i]]>x) id=fa[id][i];
	return id;
}
void count(){
	tree.build(1,1,cnt);
	for (int i=1;i<=q;i++)
		if (que[i].op==1){
			int o=jmp(que[i].x,i);
			int where=pos[tree.query(1,lef[o],rig[o])];
			write(w[where]);putchar('\n');
			if (where) tree.change(1,lef[where]);
			w[where]=0;
		}
	return;
}
int main(){
	get_data();
	prepare();
	count();
	return 0;
}

#include <bits/stdc++.h>

using namespace std;

#define N1 500005
#define N2 300005
#define N3 500005
#define ll long long
#define mod 1000000007
#define go(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define inf 0x3f3f3f3f
#define ld long double
#define pii pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define madd(a,b) (a+=(b)%mod)%=mod
#define lowb(x,c,len) lower_bound(c+1,c+len+1,x)-c
#define uppb(x,c,len) upper_bound(c+1,c+len+1,x)-c
#define ls i*2+1
#define rs i*2+2
#define mid (l+r)/2
#define lson l,mid,ls
#define rson mid+1,r,rs
#define root 1,n,0
#define l(x) (x&-x)
#define muti int T;cin>>T;while(T--)
#define G(x) for(int i=head[x];i;i=nxt[i])

int n,m,q,r=1,tmp,op[N3],x[N3],a[N1],w[N1],tim[N2],be[N1],ed[N1],fp[N1];
//vector<int>path[N1];
int tot,head[N1];
int fo[N1],nxt[N1];
int t[N1*4];
int finds(int x){return w[x]==x?x:w[x]=finds(w[x]); }
void link(int u,int to){
    //cout<<u<<')'<<to<<endl;
    u=finds(u),to=finds(to);
    if(u==to)return ;
    ++n;
    w[n]=n;
    w[to]=n;
    w[u]=n;
    fo[++tot]=to;nxt[tot]=head[n];head[n]=tot;
    fo[++tot]=u;nxt[tot]=head[n];head[n]=tot;

}

void dfs(int u){
    //cout<<u<<' '<<endl;
    fp[be[u]=++tmp]=u;
    G(u)dfs(fo[i]);
    ed[u]=tmp;
}
int cma(int x,int y){return a[x]>a[y]?x:y; }
void build(int l,int r,int i){
    t[i]=fp[l];
    if(l==r)return ;
    build(lson);build(rson);
    t[i]=cma(t[ls],t[rs]);
}
void upd(int pos,int l,int r,int i){
    if(l>r)return ;
    t[i]=fp[l];

    if(l==r)return ;
    if(pos<=mid)upd(pos,lson);
    else upd(pos,rson);
    t[i]=cma(t[ls],t[rs]);
}
int quy(int L,int R,int l,int r,int i){
    //cout<<L<<' '<<R<<' '<<l<<' '<<r<<endl;
    if(L>R)return 0;
    if(L<=l&&R>=r)return t[i];
    int res=0;
    if(L<=mid)res=cma(res,quy(L,R,lson));
    if(R>mid)res=cma(res,quy(L,R,rson));
    return res;
}
int main()
{
    cin>>n>>m>>q;
    go(i,1,n)scanf("%d",&a[i]),w[i]=i;w[n+1]=n+1;
    go(i,1,m)scanf("%d%d",&be[i],&ed[i]);
    go(i,1,q){
        scanf("%d%d",&op[i],&x[i]);
        if(op[i]==2)tim[x[i]]=1;
    }
    go(i,1,m)if(!tim[i])link(be[i],ed[i]);
    dep(i,q,1){
        if(op[i]==2)link(be[x[i]],ed[x[i]]);
        if(op[i]==1)x[i]=finds(x[i]);
    }

    go(i,1,n)if(w[i]==i)dfs(i);

    build(root);

    go(i,1,q){
        if(op[i]==2)continue;
        x[i]=quy(be[x[i]],ed[x[i]],root);
        printf("%d\n",a[x[i]]);
        a[x[i]]=0;
        upd(be[x[i]],root);
    }
}

#include <bits/stdc++.h>
using namespace std;using pr = pair<int, int>;int N, M, Q, A[200005], par[200005];pr E[300005], QS[500005];bool chk[300005];set<int> s[200005];stack<pr> st;
int f(int x) { return par[x] = (par[x] == x ? x : f(par[x])); }
void uni(int x, int y) {x = f(x), y = f(y);if(x == y) return;if(s[x].size() > s[y].size()) swap(x, y);st.push(pr(x, y));for(auto it : s[x]) s[y].insert(it);par[x] = y;}
int main() {ios::sync_with_stdio(0), cin.tie(0);cin >> N >> M >> Q;iota(par, par + N + 1, 0);
	for(int i=1; i<=N; i++) cin >> A[i], s[i].insert(A[i]);for(int i=1, x, y; i<=M; i++) {cin >> x >> y;E[i] = pr(x, y);}
	for(int i=1, x, y; i<=Q; i++) {cin >> x >> y;QS[i] = pr(x, y);if(x == 2) chk[y] = 1;}
	for(int i=1; i<=M; i++) if(!chk[i]) uni(E[i].first, E[i].second);for(int i=Q; i; i--) {if(QS[i].first == 1)QS[i].second = f(QS[i].second);
		 else {int x = E[QS[i].second].first, y = E[QS[i].second].second;if(f(x) == f(y))QS[i].first = 0;else uni(x, y);}}
	for(int i=1; i<=Q; i++) {if(QS[i].first == 1) {int p = QS[i].second;int ans = 0;if(s[p].size() > 0) {ans = *s[p].rbegin();s[p].erase(ans);}cout << ans << "\n";
		} else if(QS[i].first == 2) {int x = st.top().first, y = st.top().second; st.pop();set<int> tmp;
			for(auto it : s[x]) if(s[y].find(it) != s[y].end()) {tmp.insert(it);s[y].erase(it);}s[x] = tmp;}}}

#include <bits/stdc++.h>
using namespace std;
#undef LOCAL
#ifdef LOCAL
string to_string(string s) { return '"' + s + '"'; }
string to_string(const char* s) { return to_string(string(s)); }
string to_string(bool b) { return to_string(int(b)); }
string to_string(char b) { return "'" + string(1, b) + "'"; }
template <typename A, typename B>
string to_string(pair<A, B> p) { return "(" + to_string(p.first) + ", " + to_string(p.second) + ")"; }
template <typename A>
string to_string(A v) {
	string res = "{";
	for (const auto& x : v) res += (res == "{" ? "" : ", ") + to_string(x);
	return res + "}";
}
void debug() { cerr << endl; }
template <typename Head, typename... Tail>
void debug(Head H, Tail... T) {
	cerr << " " << to_string(H);
	debug(T...);
}
#define db(...) cerr << "[" << #__VA_ARGS__ << "]:", debug(__VA_ARGS__)
#else
#define db(...) 42
#endif
typedef long long ll;
typedef long double ld;
vector<int> P;
struct cmp {
	bool operator()(int a, int b) const {
		if (P[a] != P[b]) return P[a] > P[b];
		return a < b;
	};
};
int main() {
	int n, m, q;
	scanf("%d%d%d", &n, &m, &q);
	vector<int> A(m), B(m);
	P = vector<int>(n);
	vector<vector<int>> Q(q, vector<int>(2));
	vector<bool> rem(m);
	vector<int> idP(n + 1);
	for (int i = 0; i < n; ++i) {
		scanf("%d", &P[i]);
		idP[P[i]] = i;
	}
	for (int i = 0; i < m; ++i) {
		scanf("%d%d", &A[i], &B[i]);
		--A[i];
		--B[i];
	}
	for (int i = 0; i < q; ++i) {
		scanf("%d%d", &Q[i][0], &Q[i][1]);
		--Q[i][1];
		if (Q[i][0] == 2) {
			rem[Q[i][1]] = true;
		}
	}
	vector<int> par(n);
	iota(par.begin(), par.end(), 0);
	function<int(int)> root = [&](int a) {
		if (par[a] == a) return a;
		return par[a] = root(par[a]);
	};
	vector<vector<int>> S(n + n);
	for (int i = 0; i < n; ++i) S[i] = {i};
	for (int i = 0; i < m; ++i) {
		if (rem[i]) continue;
		int a = root(A[i]), b = root(B[i]);
		if (a == b) continue;
		if (S[a].size() < S[b].size()) swap(a, b);
		par[b] = a;
		S[a].insert(S[a].end(), S[b].begin(), S[b].end());
	}
	vector<int> newComp(q, -1);
	int nex = n;
	for (int i = q - 1; i >= 0; --i) {
		if (Q[i][0] == 2) {
			int e = Q[i][1];
			int a = root(A[e]), b = root(B[e]);
			if (a == b) continue;
			// There is a split of component at query i.
			if (S[a].size() < S[b].size()) swap(a, b);
			swap(S[b], S[nex]);
			sort(S[nex].begin(), S[nex].end(), [&](int x, int y) {
				return P[x] < P[y];
			});
			newComp[i] = nex;
			par[b] = a;
			S[a].insert(S[a].end(), S[nex].begin(), S[nex].end());
			++nex;
		}
	}
	for (int i = 0; i < n; ++i) S[i].clear();
	for (int i = 1; i <= n; ++i) {
		int ii = idP[i];
		root(ii);
		S[par[ii]].push_back(ii);
	}
	for (int i = 0; i < q; ++i) {
		if (Q[i][0] == 1) {
			int r = par[Q[i][1]];
			int val = 0;
			while (!S[r].empty()) {
				int mx = S[r].back();
				S[r].pop_back();
				if (par[mx] != r) continue;
				if (P[mx] == 0) continue;
				val = P[mx];
				P[mx] = 0;
				break;
			}
			printf("%d\n", val);
		} else {
			db(2, i, Q[i][1]);
			if (newComp[i] == -1) continue;
			int r = newComp[i];
			db(r);
			for (int x : S[r]) {
				par[x] = r;
			}
		}
	}
}

/*--------------------------------------------------------------------
      JENISH MONPARA S.       IIT PATNA         I LOVE ADITI GOEL
--------------------------------------------------------------------*/
#include <bits/stdc++.h>
using namespace std;
long double PI = 3.14159265359;
long double DEL = 1e-10;
int mod =  1000000007;

#define ftt cin>>t;for(int tt=1;tt<=t;++tt)
#define all(a) a.begin() , a.end()
#define sqr(a) ((a) * (a))
#define double long double
#define dbg cout<<"\nhi\n"
#define int long long
#define nl cout<<"\n"
#define pb push_back
#define sp <<" "<<
#define ss second
#define ff first

const int N = 400050;
int cnt, sum, mid, mx, mn, ans, a[N], b[N];
int n, m, d, i, j, k, l, p, que, r, w, x[N], y[N], del[N];
bool f, f1, f2;
string s;
// you can also use __int128
// priority_queue<int,vector<int>,greater<int>>
// bitset<100>(x).count()
//******************************************* CHECK CONSTRAINTS **************************************************
pair<int,int> t[N*4],q[2*N];
int check[2*N],timer = 1,tin[N],tout[N];
vector<int> g[N];

int find(int i)
{
      if(i == a[i])
      {
            return i;
      }
      return a[i] = find(a[i]);
}

void join(int x,int y)
{
      int parx = find(x),pary = find(y);
      if(parx == pary)
      {
            return;
      }
      n++;
      a[parx] = n;
      a[pary] = n;
      a[n] = n;
      g[n].push_back(parx);
      g[n].push_back(pary);
}

void dfs(int i)
{
      tin[i] = timer++;
      for(auto j:g[i])
      {
            dfs(j);
      }
      tout[i] = timer;
}

void update(int i,int l,int r,int x,pair<int,int> v)
{
      if(x < l || x > r || l > r)
      {
            return;
      }
      if(l == r)
      {
            t[i] = v;
            return;
      }
      int y = 2*i;
      update(y,l,(l+r)/2,x,v);
      update(y|1,(l+r+2)/2,r,x,v);
      t[i] = max(t[y],t[y|1]);
}

pair<int, int> query(int i,int l,int r,int a,int b)
{
      if(a <= l and r <= b)
      {
            return t[i];
      }
      if(a > r || b < l || l > r)
      {
            return {0,0};
      }
      int y = 2*i;
      return max(query(y,l,(l+r)/2,a,b),query(y|1,(l+r+2)/2,r,a,b));
}

int32_t main()
{
      ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
      cin>>n>>m>>que;
      for(int i=1;i<=n;i++)
      {
            cin>>b[i];
            a[i] = i;
      }
      for(int i=1;i<=m;i++)
      {
            cin>>x[i]>>y[i];
      }
      for(int i=1;i<=que;i++)
      {
            cin>>q[i].ff>>q[i].ss;
            if(q[i].ff == 2)
            {
                  del[q[i].ss] = 1;
            }
      }
      for(int i=1;i<=m;i++)
      {
            if(!del[i])
            {
                  join(x[i],y[i]);
            }
      }
      for(int i=que;i>0;i--)
      {
            if(q[i].ff == 1)
            {
                  check[i] = find(q[i].ss);
            }
            else
            {
                  join(x[q[i].ss],y[q[i].ss]);
            }
      }
      for(int i=1;i<=n;i++)
      {
            if(a[i] == i)
            {
                  dfs(i);
            }
      }
      for(int i=1;i<=n;i++)
      {
            update(1,1,timer,tin[i],{b[i],tin[i]});
      }
      //cerr<<timer sp n;nl;
      //timer--;
      //assert(timer == n);
      for(int i=1;i<=que;i++)
      {
            if(q[i].ff == 1)
            {
                  k = check[i];
                  auto j = query(1,1,timer,tin[k],tout[k]-1);
                  update(1,1,timer,j.ss,{0,j.ss});
                  cout<<j.ff;nl;
            }
      }
}

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,r,l) for(int i=(r);i>=(l);--i)
#define For(i,u) for(int i=hed[u],v=e[i].to;i;i=e[i].nex,v=e[i].to)
#define fi first
#define se second
#define mp make_pair
using namespace std;
const int N=5e5+10;
int f[N],sz[N],hed[N],ed,n,m,Q,id[N],opt[N],a[N],u[N],v[N],del[N],p[N];
set<pair<int,int> > s[N];bool ban[N];
struct edge{
	int to,nex;bool vis;
	edge(int _=0,int __=0):to(_),nex(__),vis(0){}
}e[N<<1];
inline void add(int u,int v){e[++ed]=edge(v,hed[u]);hed[u]=ed;}
int gfa(int x){return f[x]^x?(f[x]=gfa(f[x])):x;}
void merge(int u,int v){u=gfa(u);v=gfa(v);if(sz[u]>=sz[v]) swap(u,v);f[u]=v;sz[v]+=sz[u];}
void dfs(int u,int fa,int x,int y){
	f[u]=x;s[y].erase(mp(a[u],u));s[x].insert(mp(a[u],u));
	For(i,u) if((v^fa)&&!e[i].vis) dfs(v,u,x,y);
}
int main(){
	scanf("%d%d%d",&n,&m,&Q);ed=1;
	rep(i,1,n) scanf("%d",a+i),f[i]=i,sz[i]=1;
	rep(i,1,m) scanf("%d%d",u+i,v+i);
	rep(i,1,Q) scanf("%d%d",opt+i,id+i);
	rep(i,1,Q) if(opt[i]==2) ban[id[i]]=1;
	rep(i,1,m) if(gfa(u[i])^gfa(v[i])&&!ban[i]) merge(u[i],v[i]),add(u[i],v[i]),add(v[i],u[i]);
	per(i,Q,1) if(opt[i]==2&&(gfa(u[id[i]])^gfa(v[id[i]]))){
		int x=gfa(u[id[i]]),y=gfa(v[id[i]]);
		add(u[id[i]],v[id[i]]),add(v[id[i]],u[id[i]]);
		del[i]=sz[x]<sz[y]?ed:ed-1;p[i]=sz[x]<sz[y]?x:y;merge(x,y);
	}
	rep(i,1,n) s[gfa(i)].insert(mp(a[i],i));
	rep(i,1,Q){
		if(opt[i]==1){
			int u=gfa(id[i]),x=s[u].rbegin()->se;
			printf("%d\n",a[x]);a[x]=0;
			s[u].erase(*s[u].rbegin());s[u].insert(mp(0,x));
		}
		else if(del[i]){
			int x=e[del[i]].to;e[del[i]].vis=e[del[i]^1].vis=1;
			dfs(x,0,p[i],gfa(x));
		}
	}
	return 0;
}

#include<bits/stdc++.h>
using namespace std;

#define fs first
#define sc second
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)x.size()
#define pb push_back
#define fastio ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define MP make_pair
#define sqr(x) ((x) * (x))
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const int N = 5e5 + 100, INF = 1e9;
vector<int> g[N];
int par[N], tin[N], tout[N], val[N];
pair<int, int> t[4 * N];
int cur_size, timer = 0;

int get(int v) {
    if (v == par[v]) {
        return v;
    }
    return par[v] = get(par[v]);
}

void unite(int a, int b) {
    a = get(a);
    b = get(b);
    if (a == b) {
        return;
    }
    int v = cur_size++;

    g[v].pb(a);
    g[v].pb(b);
    par[a] = par[b] = v;
}

void dfs(int v) {
    tin[v] = timer++;
    for (auto u : g[v]) {
        dfs(u);
    }
    tout[v] = timer;
}

void upd(int v, int l, int r, int pos, pair<int, int> x) {
    if (l + 1 == r) {
        t[v] = x;
        return;
    }
    int mid = (l + r) / 2;
    if (pos < mid) upd(v * 2 + 1, l, mid, pos, x);
    else upd(v * 2 + 2, mid, r, pos, x);
    t[v] = max(t[v * 2 + 1], t[v * 2 + 2]);
}

pair<int, int> qu(int v, int l, int r, int ql, int qr) {
    if (qr <= l || r <= ql) return {-INF, -INF};
    if (ql <= l && r <= qr) return t[v];
    int mid = (l + r) / 2;
    return max(qu(v * 2 + 1, l, mid, ql, qr), qu(v * 2 + 2, mid, r, ql, qr));
}

signed main() {
    fastio;
    #ifdef FlameDragon
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif

    for (int i = 0; i < N; i++) {
        par[i] = i;
    }

    int n, m, q;
    cin >> n >> m >> q;
    cur_size = n;
    vector<pair<int, int>> queries(q);
    vector<pair<int, int>> edges(m);
    vector<int> deleted(m);
    for (int i = 0; i < n; i++) {
        cin >> val[i];
    }
    for (int i = 0; i < m; i++) {
        cin >> edges[i].fs >> edges[i].sc;
        edges[i].fs--; edges[i].sc--;
    }

    for (int i = 0; i < q; i++) {
        int type, id;
        cin >> type >> id;
        id--;
        if (type == 2) deleted[id] = 1;
        queries[i] = {type, id};
    }
    for (int i = 0; i < m; i++) {
        if (!deleted[i]) unite(edges[i].fs, edges[i].sc);
    }

    for (int i = q - 1; i >= 0; i--) {
        int type = queries[i].fs;
        if (type == 1) {
            queries[i].sc = get(queries[i].sc);
        } else {
            int id = queries[i].sc;
            unite(edges[id].fs, edges[id].sc);
        }
    }
    for (int i = 0; i < cur_size; i++) {
        if (par[i] == i) {
            dfs(i);
        }
    }

    for (int i = 0; i < cur_size; i++) {
        upd(0, 0, timer, tin[i], {val[i], i});
    }

    for (int i = 0; i < q; i++) {
        int type = queries[i].fs;
        // cout << 'f';
        if (type == 2) continue;
        int v = queries[i].sc;
        // cout << tin[v] << ' ' << tout[v] << endl;
        auto ans = qu(0, 0, timer, tin[v], tout[v]);
        cout << ans.fs << '\n';
        if (ans.fs != 0) {
            int u = ans.sc;
            upd(0, 0, timer, tin[u], {0, 0});
        }
    }
    // cout << 'f';
}

#include <cstdio>
#include <vector>
using namespace std;
const int MAXN=500005;
int n, m, q, num, dfc;
int a[MAXN], w[MAXN];
int u[MAXN], v[MAXN], f[MAXN];
int opt[MAXN], ob[MAXN], p[MAXN];
bool cut[MAXN];
int op[MAXN], cl[MAXN];
vector<int> G[MAXN];
int getf(int x)
{
	if (x==f[x]) return x;
	return f[x]=getf(f[x]);
}
void merge(int u, int v)
{
	int x=getf(u), y=getf(v);
	if (x!=y)
	{
		f[x]=f[y]=++num;
		G[num].push_back(x);
		G[num].push_back(y);
	}
}
void DFS(int u)
{
	op[u]=++dfc;
	for (int v: G[u]) DFS(v);
	cl[u]=dfc;
}
namespace SGT
{
	struct Node
	{
		int l, r;
		pair<int, int> val;
	} tr[4*MAXN];
#define lc (o<<1)
#define rc (o<<1|1)
	void pushup(int o)
	{
		tr[o].val=max(tr[lc].val, tr[rc].val);
	}
	void build(int o, int l, int r, int* a)
	{
		tr[o].l=l, tr[o].r=r;
		if (l==r) return tr[o].val=make_pair(a[l], l), void();
		int mid=(l+r)>>1;
		build(lc, l, mid, a);
		build(rc, mid+1, r, a);
		pushup(o);
	}
	pair<int, int> query(int o, int l, int r)
	{
		if (tr[o].l>r||tr[o].r<l) return make_pair(0, 0);
		if (l<=tr[o].l&&tr[o].r<=r) return tr[o].val;
		return max(query(lc, l, r), query(rc, l, r));
	}
	void modify(int o, int p)
	{
		if (tr[o].l==tr[o].r) return tr[o].val.first=0, void();
		int mid=(tr[o].l+tr[o].r)>>1;
		if (p<=mid) modify(lc, p);
		else modify(rc, p);
		pushup(o);
	}
#undef lc
#undef rc
}
int main()
{
//	freopen("D.in", "r", stdin);
//	freopen("D.out", "w", stdout);
	scanf("%d%d%d", &n, &m, &q);
	for (int i=1; i<=n; i++) scanf("%d", &a[i]);
	for (int i=1; i<=m; i++) scanf("%d%d", &u[i], &v[i]);
	for (int i=1; i<=n+m; i++) f[i]=i;
	for (int i=1; i<=q; i++)
	{
		scanf("%d%d", &opt[i], &ob[i]);
		if (opt[i]==2) cut[ob[i]]=1;
	}
	num=n;
	for (int i=1; i<=m; i++)
		if (!cut[i]) merge(u[i], v[i]);
	for (int i=q; i>=1; i--)
		if (opt[i]==1) p[i]=getf(ob[i]);
		else merge(u[ob[i]], v[ob[i]]);
	for (int i=1; i<=num; i++)
		if (getf(i)==i) DFS(i);
	for (int i=1; i<=num; i++) w[op[i]]=a[i];
	SGT::build(1, 1, num, w);
	for (int i=1; i<=q; i++)
		if (opt[i]==1)
		{
			auto ret=SGT::query(1, op[p[i]], cl[p[i]]);
			printf("%d\n", ret.first);
			SGT::modify(1, ret.second);
		}
	return 0;
}

#include <bits/stdc++.h>
//#define ACM_LOCAL
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const int N = 4e5 + 10;
const int M = 1e6 + 10;
const int MOD = 1e9 + 7;

struct Hash {
    int b[N], tot;
    void init() { tot = 0; }
    void insert(int x) { b[++tot] = x; }
    void build() {
        sort(b + 1, b + 1 + tot);
        tot = unique(b + 1, b + 1 + tot) - (b + 1);
    }
    int pos(int x) { return lower_bound(b + 1, b + 1 + tot, x) - b; }
} ha;
struct Edge {
    int u, v, w;
    bool operator < (const Edge &rhs) const {
        return w < rhs.w;
        // > 最大边中的最小值
        // < 最小边中的最大值
    }
} e[M];

int n, m, d[N], dfn[N], t, f[N][20], q, idx, rnk[N], in[N], out[N];
int cnt, val[N], fa[N], a[N];
int rt[N], NodeNum;
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }

vector<int> g[N];

void dfs(int x, int fa) {
    rnk[dfn[x] = ++idx] = x, f[x][0] = fa, d[x] = d[fa] + 1;
    for (int i = 1; i <= 19; i++) f[x][i] = f[f[x][i-1]][i-1];
    in[x] = idx;
    for (auto &y : g[x])
        if (y != fa) dfs(y, x);
    out[x] = idx;
}

void exKruskal() {
    cnt = n; for (int i = 1; i < (n << 1); i++) fa[i] = i;
    sort(e + 1, e + 1 + m);
    for (int i = 1; i <= m; i++) {
        int u = find(e[i].u), v = find(e[i].v);
        if (u == v) continue;
        val[++cnt] = e[i].w;
        fa[u] = fa[v] = cnt;
        g[u].push_back(cnt), g[cnt].push_back(u);
        g[v].push_back(cnt), g[cnt].push_back(v);
        if (cnt == (n << 1) - 1) break;//最多2N-1个点
    }
    for (int i = 1; i <= cnt; i++)
        if (!d[i]) {//未访问过
            int rt = find(i);//下树剖lca
            dfs(rt, 0);
        }
}
int FindPoint (int x, int p) {
    for (int i = 20; i >= 0; i--)
        if (d[x] > (1 << i) && val[f[x][i]] <= p) x = f[x][i];
    return x;
}

struct Node {
    int L[N<<2], R[N<<2], maxx[N<<2], id[N<<2];

    void push_up(int u) {
        if (maxx[u<<1] >= maxx[u<<1|1]) {
            maxx[u] = maxx[u<<1];
            id[u] = id[u<<1];
        }
        else {
            maxx[u] = maxx[u<<1|1];
            id[u] = id[u<<1|1];
        }
    }
    void build(int u, int l, int r) {
        L[u] = l, R[u] = r;
        if (l == r) {
            maxx[u] = a[rnk[l]];
            id[u] = l;
            return;
        }
        int mid = l + r >> 1;
        build(u<<1, l, mid);
        build(u<<1|1, mid+1, r);
        push_up(u);
    }
    void modify(int u, int pos, int val) {
        if (L[u] == R[u]) {
            maxx[u] = val;
            return;
        }
        int mid = L[u] + R[u] >> 1;
        if (pos <= mid) modify(u<<1, pos, val);
        else modify(u<<1|1, pos, val);
        push_up(u);
    }
    PII query(int u, int ql, int qr) {
        if (ql <= L[u] && qr >= R[u]) {
            return {maxx[u], id[u]};
        }
        int mid = L[u] + R[u] >> 1;
        PII Max = {0, 0};
        if (ql <= mid) Max = max(query(u<<1, ql, qr), Max);
        if (qr > mid) Max = max(query(u<<1|1, ql, qr), Max);
        return Max;
    }
}tr;
struct Q {
    int opt, x;
}qry[M];

void ask(int x, int p) {
    int Point = FindPoint(x, p);
    PII Max = tr.query(1, in[Point], out[Point]);
    printf("%d\n", Max.first);
    tr.modify(1, Max.second, 0);
}

void solve() {
    cin >> n >> m >> q;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= m; i++) {
        int u, v;
        cin >> u >> v;
        e[i] = {u, v, 1};
    }
    for (int i = 1; i <= q; i++) {
        cin >> qry[i].opt >> qry[i].x;
        if (qry[i].opt == 2) e[qry[i].x].w = INF - i;
    }
    exKruskal();
    tr.build(1, 1, idx);
    for (int i = 1; i <= q; i++) {
        int p = INF - i;
        if (qry[i].opt == 1) {
            ask(qry[i].x, p);
        }
    }

}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
    return 0;
}

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define mkp make_pair
#define rint register int
#define INF ((1 << 30) - 1)
#define FI(n) FastIO::read(n)
#define FO(n) FastIO::write(n)
#define Pair pair < int, int >
#define mst(a,b) memset(a,b,sizeof(a))
#define foR(i, k, j) for(rint i = (k); i >= (j); i--)
#define For(i, k, j) for(rint i = (k); i <= (j); i++)
#define Foe(i, u) for(rint i = lst[u], v = e[i].v; i; i = e[i].nxt, v = e[i].v)
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define file(s) freopen(s".in", "r", stdin); freopen(s".out", "w", stdout)
//#define int long long
const int P = 1000000007; //
using namespace std;
inline void ckmax(int &a, int b) {a = max(a, b);}
inline void ckmin(int &a, int b) {a = min(a, b);}
inline void mulmod(int &a, int b) {a = 1ll * a * b % P;}
inline void addmod(int &a, int b) {int t = a + b; a = (t >= P ? t - P : t); }
inline int ksm(int a, int b) {int ans=1; for(;b;b>>=1) {if(b&1) ans=1ll*ans*a%P;a=1ll*a*a%P;}return ans;}
inline int inv(int a) {return ksm(a, P-2);}

inline void printarray(int *a, int n) {For(i, 1, n) fprintf(stderr, "%d ", a[i]); fprintf(stderr, "\n");}
namespace FastIO {
    const int SIZE=1<<16; char buf[SIZE], obuf[SIZE], str[64]; int bi=SIZE, bn=SIZE, opt;
    int read(char *s) {
        while (bn) {for (;bi<bn&&buf[bi]<=' ';bi++);if (bi<bn) break; bn=fread(buf,1,SIZE,stdin),bi=0;}
        int sn=0;while (bn) {for (;bi<bn&&buf[bi]>' ';bi++) s[sn++]=buf[bi];if (bi<bn) break; bn=fread(buf,1,SIZE,stdin),bi=0;}s[sn]=0;return sn;
    }
    bool read(int& x) {if(x)x=0;int bf=0,n=read(str); if(!n) return 0; int i=0; if (str[i]=='-') bf=1,i=1; for(x=0;i<n;i++) x=x*10+str[i]-'0'; if(bf) x=-x; return 1;}
    void write(int x) {
        if(!x) obuf[opt++] = '0'; else {if(x<0) obuf[opt++]='-',x=-x;int sn=0; while(x)str[sn++]=x%10+'0',x/=10;for (int i=sn-1;i>=0;i--) obuf[opt++]=str[i];}
        if (opt>=(SIZE>>1)){fwrite(obuf, 1, opt, stdout); opt=0;}
    }
    void write(char x) {obuf[opt++]=x;if (opt>=(SIZE>>1)){fwrite(obuf, 1, opt, stdout); opt=0;}}
    void Fflush() { if (opt) fwrite(obuf, 1, opt, stdout); opt=0;}
};
const int MAXN = 1e6 + 5;
int n, m, q, a[MAXN], o[MAXN], p[MAXN], u[MAXN], v[MAXN], used[MAXN];
vector < int > e[MAXN];

int f[MAXN], cnt = 0;
inline int find(int x) {
	while(x != f[x]) x = f[x] = f[f[x]];
	return x;
}
inline void merge(int x, int y) {
	x = find(x), y = find(y);
	if(x == y) return;
	cnt++; e[cnt].pb(f[x]), e[cnt].pb(f[y]);
	f[x] = f[y] = cnt;
}

int dfn[MAXN], id[MAXN], siz[MAXN], ind;
inline void dfs(int u) {
	id[dfn[u] = ++ind] = u, siz[u] = 1;
	for(auto v : e[u]) {
		dfs(v), siz[u] += siz[v];
	}
}
struct Segment_tree {
	pair < int, int > mx[MAXN << 2];
	#define ls (k << 1)
	#define rs (k << 1 | 1)
	#define mid ((l + r) >> 1)
	pair < int, int > merge(pair < int, int > a, pair < int, int > b) {
		if(a.first > b.first) return a;
		else return b;
	}
	void update(int k, int l, int r, int pos, int val) {
		if(l == r) return mx[k] = mkp(val, l), void();
		pos <= mid ? update(ls, l, mid, pos, val) : update(rs, mid+1, r, pos, val);
		mx[k] = merge(mx[ls], mx[rs]);
	}

	Pair query(int k, int l, int r, int ql, int qr) {
		if(l == ql && r == qr) return mx[k];
		if(qr <= mid) return query(ls, l, mid, ql, qr);
		if(mid < ql) return query(rs, mid+1, r, ql, qr);
		return merge(query(ls, l, mid, ql, mid), query(rs, mid+1, r, mid+1, qr));
	}
}tr;
signed main()
{
    #ifndef ONLINE_JUDGE
        file("pro");
    #endif
    cin >> n >> m >> q;
    For(i, 1, n) FI(a[i]);
    For(i, 1, m) FI(u[i]), FI(v[i]);
    For(i, 1, q) {
    	FI(o[i]), FI(p[i]);
    	if(o[i] == 2) used[p[i]] = 1;
	}
	For(i, 1, 2 * n) f[i] = i; cnt = n;
	For(i, 1, m)
		if(!used[i]) merge(u[i], v[i]);
    foR(i, q, 1) {
    	if(o[i] == 1) p[i] = find(p[i]);
		else merge(u[p[i]], v[p[i]]);
	}
//	cerr << "?";
	cnt++;
	For(i, 1, cnt - 1)
		if(find(i) == i) e[cnt].pb(i);
	dfs(cnt);
//	For(i, 1, n) cerr << dfn[i] << endl;
	For(i, 1, n) tr.update(1, 1, cnt, dfn[i], a[i]);
	For(i, 1, q) {
		if(o[i] == 1) {
//			cerr << p[i] << endl;
//			cerr << dfn[p[i]] << ' ' << dfn[p[i]] + siz[p[i]] - 1 << endl;
			Pair res = tr.query(1, 1, cnt, dfn[p[i]], dfn[p[i]] + siz[p[i]] - 1);
			printf("%d\n", res.first);
//			cerr << res.second << endl;
			tr.update(1, 1, cnt, res.second, 0);
		}
	}
    return 0;
}
/*

4 7 1
2 1 8
2 4 2
4 3 2
3 2 8
2 3 5
4 3 1
2 4 5
2 9
*/

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pi;
typedef pair<ll,ll> pl;
#define F first
#define S second
#define endl '\n'
#define all(x) (x).begin(),(x).end()
#ifdef dremix
    #define p(x) cerr<<#x<<" = "<<x<<endl;
    #define p2(x,y) cerr<<#x<<" , "<<#y<<" = "<<x<<" , "<<y<<endl;
    #define pp(x) cerr<<#x<<" = ("<<x.F<<" , "<<x.S<<")"<<endl;
    #define pv(x) cerr<<#x<<" = {";for(auto u : x)cerr<<u<<", ";cerr<<"}"<<endl;
    #define ppv(x) cerr<<#x<<" = {";for(auto u : x)cerr<<u.F<<"-"<<u.S<<", ";cerr<<"}"<<endl;
#else
    #define p(x)
    #define p2(x,y)
    #define pp(x)
    #define pv(x)
    #define ppv(x)
#endif
#define fastio ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int maxp = 22;
const ld EPS = 1e-18;
const ll INF = 1e18;
const int MOD = 1e9+7;
const int N = 6e5+1;

vector<vector<int> > a(N);
vector<int> par(N);
int n;

int find(int x){
    return (par[x] == x) ? x : par[x] = find(par[x]);
}

void join(int x, int y){
    x = find(x);
    y = find(y);
    if(x==y)return;

    n++;
    par[x] = n;
    par[y] = n;
    par[n] = n;
    a[n].push_back(x);
    a[n].push_back(y);
}

int tin[N],tout[N];
int curr = 1;

void dfs(int s){
    tin[s] = curr++;
    for(auto x : a[s])
        dfs(x);
    tout[s] = curr;
}

pi seg[N*4];

void update(int s, int e, int idx, int k, int x){
    if(s==e && s==k){
        seg[idx] = {x,s};
        return;
    }
    if(s>k || e<k)return;
    int mid = (s+e)/2;
    update(s,mid,idx*2,k,x);
    update(mid+1,e,idx*2+1,k,x);

    seg[idx] = max(seg[idx*2],seg[idx*2+1]);
}

pi query(int s, int e, int idx, int qs, int qe){
    if(qs<=s && e<=qe)return seg[idx];
    if(s>qe || e<qs)return {0,0};
    int mid = (s+e)/2;

    return max(query(s,mid,idx*2,qs,qe),query(mid+1,e,idx*2+1,qs,qe));
}

int main(){
fastio

int m,q;
cin>>n>>m>>q;

int i,arr[n+1];

int ini = n;
for(i=1;i<=n;i++)cin>>arr[i];

pi edge[m+1];

for(i=1;i<=m;i++)cin>>edge[i].F>>edge[i].S;

for(i=1;i<=n;i++)par[i] = i;

pi ask[q];
bool rem[m+1]={};

for(i=0;i<q;i++){
    cin>>ask[i].F>>ask[i].S;
    if(ask[i].F==2){
        rem[ask[i].S] = true;
    }
}

for(i=1;i<=m;i++){
    if(rem[i])continue;
    join(edge[i].F,edge[i].S);
}

vector<int> ans;

for(i=q-1;i>=0;i--){
    if(ask[i].F==1){
        ans.push_back(find(ask[i].S));
    }
    else{
        join(edge[ask[i].S].F,edge[ask[i].S].S);
    }
}

for(i=1;i<=n;i++){
    if(find(i)==i){
        //cout<<i<<endl;
        dfs(i);
    }
}

for(i=1;i<=n;i++){
    p2(tin[i],tout[i])
}

for(i=1;i<=ini;i++){
    p2(tin[i],arr[i])
    update(1,n,1,tin[i],arr[i]);
}

reverse(all(ans));
pv(ans)
p(n)

for(auto x : ans){
    p2(tin[x],tout[x]-1)
    p(x)

    pi res = query(1,n,1,tin[x],tout[x]-1);
    pp(res)
    cout<<res.F<<endl;
    if(res.S)
        update(1,n,1,res.S,0);
}

}

#include<bits/stdc++.h>
using namespace std;

#define endl "\n"
#define LL long long
#define ULL unsigned long long
const LL        INF = 1LL<<59;
const double    PI = 2.0 * acos(0.0);

typedef pair<int,int> pii;
typedef pair<LL,LL> pll;
typedef vector<int> vi;
typedef vector<LL> vl;
typedef vector<pii> vii;
typedef vector<pll> vll;

//// Including Policy Based DS
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
//using namespace __gnu_pbds;
//
/////cout<<*X.find_by_order(1)<<endl;
/////cout<<X.order_of_key(-5)<<endl;
//
//typedef tree<
//int,
//null_type,
//less< int >,
//rb_tree_tag,
//tree_order_statistics_node_update>
//ordered_set;

#define READ        freopen("in.txt","r",stdin)
#define WRITE       freopen("out.txt","w",stdout)
#define BOOST		ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define sf 			scanf
#define pf 			printf
#define F  			first
#define S  			second
#define pb 			push_back
#define NL			pf("\n")
#define ALL(v)		v.begin(),v.end()
#define si(x)		sf("%d",&x);
#define sii(x,y)	sf("%d%d",&x,&y);
#define siii(x,y,z)	sf("%d%d%d",&x,&y,&z);
#define sl(x)		sf("%lld",&x);
#define sll(x,y)	sf("%lld%lld",&x,&y);
#define slll(x,y,z)	sf("%lld%lld%lld",&x,&y,&z);
#define sqr(x)      ( (x) * (x) )
#define mem(x,y) 	memset(x,y,sizeof x )
#define ch 			printf("Came Here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
#define deb(x)      cerr<<#x<<" :: "<<x<<"\n"
#define SV(v)		sort(v.begin(),v.end())
#define SVR(v,cmp)	sort(v.begin(),v.end(),cmp)
#define FOR(i,n)	for(int i=0;i<n;i++)
#define cnd			tree[idx]
#define lc			tree[idx*2]
#define rc			tree[idx*2+1]
#define lnd 		(2*idx),(b),( (b+e) /2 )
#define rnd 		((2*idx)+1),(((b+e)/2)+1),(e)

// graph direction array [4]
int X[4]={0,0,-1,1};
int Y[4]={1,-1,0,0};
// graph direction array [8]
//int X[8]={0,0,1,-1,-1,1,1,-1};
//int Y[8]={1,-1,0,0,-1,-1,1,1};
// Bishop direction array [8]
//int BX[8]={0,0,1,-1,-1,1,1,-1};
//int BY[8]={1,-1,0,0,-1,-1,1,1};
// Knight Direction Array
//int KX[8] = {1,1,2,2,-1,-1,-2,-2};
//int KY[8] = {2,-2,1,-1,2,-2,1,-1};

// Bit Operations
#define popcountL   __builtin_popcountll
#define popcount    __builtin_popcount
inline bool checkBit(int N,int pos){return (bool)(N & (1<<pos));} // check bit
inline int setBit(int N,int pos){ return N=N | (1<<pos);}// set bit
inline int unsetBit(int N,int pos){	return N=( N & ( ~( 1<<pos ) ) );}// unset bit
inline int toggleBit(int N,int pos){ return N = ( N ^(1<<pos) ); }// toggle bit

inline LL modMul(LL a, LL b,LL mod){
    LL ans = 0;
    a = a % mod;
    while (b > 0){
        if ( b % 2 )ans = (ans%mod+ a%mod) % mod;
        a = (a%mod * 2%mod) % mod;
        b /= 2;
    }
    return ans % mod;
}
inline LL powerMod(LL a,LL b,LL mod){
	if(b==0)return 1LL%mod;
	LL x=powerMod( a,b/2,mod );
	x = ( x%mod * x%mod ) % mod;
	if( b%2==1 )x = ( x%mod * a%mod ) % mod;
	return x%mod;
}
inline LL lcm( LL a,LL b ){
	LL g = __gcd(a,b);
	return ((a/g) * b);
}

//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
const int mx = 2e6+5;

int arr[mx];

vi dg[mx];
int par[mx];
int find_par(int u){
    if( u == par[u] )return u;
    return par[u] = find_par(par[u]);
}
int compo;
void merge_set(int u,int v){
    int a = find_par(u);
    int b = find_par(v);
    if(a!=b){
        compo++;
        par[compo] = compo;
        par[a] = compo;
        par[b] = compo;
        dg[compo].pb(a);
        dg[compo].pb(b);
    }
}

int st[mx];
int fin[mx];
bool erased[mx];
pii E[mx];
pii Q[mx];
vi queryNodes;
int __tim;
void dfs(int u,int p){
    st[u] = ++__tim;
    for(int v:dg[u]){
        if(v!=p){
            dfs(v,u);
        }
    }
    fin[u] = ++__tim;
}

pii tree[4*mx];
void update(int idx,int b,int e,int pos,pii v){
    if(b==e && b==pos){
        cnd = v;
        return;
    }
    int mid = (b+e)>>1;
    if(pos<=mid)update(lnd,pos,v);
    else update(rnd,pos,v);
    cnd = max(lc,rc);
}

pii query(int idx,int b,int e,int l,int r){
    if( l>e || r<b )return pii(0,0);
    if( l<=b && r>=e )return cnd;
    return max(query(lnd,l,r),query(rnd,l,r));
}

int main(){
    BOOST;
    #ifdef MujahidPC
        double start = clock();
//        READ;
//        WRITE;
    #endif
    int t,n,m,q;

    cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
        cin>>arr[i];
    }

    FOR(i,m){
        cin>>E[i+1].first>>E[i+1].second;
    }

    FOR(i,q){
        int x,y;
        cin>>x>>y;
        Q[i] = pii(x,y);
        if(x==2){
            erased[y] = 1;
        }
    }
    compo = n;
    for(int i=1;i<=n;i++)par[i] = i;
    __tim = 0;
    for(int i=1;i<=m;i++){
        if(!erased[i]) {
            merge_set(E[i].first,E[i].second);
        }
    }

    for(int i=q-1;i>=0;i--){
        if( Q[i].first == 1 ){
            int p = find_par(Q[i].second);
            queryNodes.pb(p);
        }
        else{
            int id = Q[i].second;
            int u = E[id].first;
            int v = E[id].second;
            merge_set(u,v);
        }
    }

    for(int i=1;i<=compo;i++){
        if( find_par(i) == i ){
            dfs(i,-1);
        }
    }

    int lst = fin[compo] + 1;
    for(int i=1;i<=compo;i++){
        update(1,1,lst,st[i],pii(arr[i],i));
    }
    reverse(ALL(queryNodes));
    for(int v:queryNodes){
        int l = st[v],r = fin[v];
        pii cur = query(1,1,lst,l,r);
        cout<<cur.first<<endl;
        if( cur.first!=0 ){
            int u = cur.second;
            update(1,1,lst,st[u],pii(0,0));
        }
    }

    #ifdef MujahidPC
        double tim = (clock() - start)/CLOCKS_PER_SEC;
        cerr<<"Running Time : "<<tim<<" \n";
    #endif
    return 0;
}

#include<bits/stdc++.h>

namespace mem{ //v1.8.2 => size: 13.11KiB
  #define MEM_IO
  #define MEM_STR
  #define MEM_MATH
  #define MEM_UTILS
  #define MEM_MODINT
  #define MEM_RANDOM
  #define MEM_STDVAL
  #define MEM_CONTAINER
  #ifdef memset0
  #else
    #define MEM_FASTIO
  #endif

  #ifdef __SIZEOF_INT128__
    #define MEM_INT128
  #endif

  #define __integer_mapper(func)     \
      func(int)                      \
      func(unsigned int)             \
      func(long long)                \
      func(unsigned long long)
  #define __float_mapper(func)       \
      func(float)                    \
      func(double)
  #define __string_mapper(func) \
      func(char *)              \
      func(string &)            \
      func(std::string &)
  #define __string_join_mapper(func)                                              \
      func(vector<string>,string)                                                 \
      func(std::vector<string>,string)                                            \
      template<class T> func(vector<T>,to_string)                                 \
      template<class T> func(std::vector<T>,to_string)

  #ifdef MEM_STDVAL
    namespace stdval{
      using i32=int;
      using i64=long long;
      using u32=unsigned int;
      using u64=unsigned long long;
      using f32=float;
      using f64=double;
  #ifdef MEM_INT128
      using i128=__int128_t;
      using u128=__uint128_t;
  #endif
    }
  #endif

  #ifdef MEM_UTILS
    namespace utils{
      using std::cin;
      using std::tie;
      using std::cout;
      using std::cerr;
      using std::endl;
      using std::swap;
      using std::sort;
      using std::reverse;
      using std::shuffle;
      using std::function;
      using std::make_pair;
      using std::make_tuple;
      using std::lower_bound;
      using std::upper_bound;
      using std::max_element;
      using std::min_element;
    }
  #endif

  #ifdef MEM_IO
    namespace io{
  #ifdef MEM_FASTIO
      namespace fastio{
        const int BUFFER=1<<21;
        char ibuf[BUFFER],*iS,*iT;
        inline int getc(){
          if(iS==iT){
            iT=(iS=ibuf)+fread(ibuf,1,BUFFER,stdin);
            return iS==iT?EOF:*iS++;
          }else{
            return *iS++;
          }
        }
        char obuf[BUFFER],*oS=obuf,*oT=oS+BUFFER-1;
        inline void flush(){
          fwrite(obuf,1,oS-obuf,stdout);
          oS=obuf;
        }
        inline void putc(int x){
          *oS++=x;
          if(oS==oT)flush();
        }
        struct Flusher{~Flusher(){flush();}}flusher;
      }
      using fastio::getc;
      using fastio::putc;
  #else
      inline int getc(){return getchar();}
      inline void putc(int c){putchar(c);}
  #endif

      template<class T> inline void readDigit(T &x){
        x=getc();
        while(!isdigit(x))x=getc();
      }
      inline int readDigit(){
        int x;
        readDigit(x);
        return x;
      }
      template<class T> inline void readAlpha(T &x){
        x=getc();
        while(!isalpha(x))x=getc();
      }
      inline int readAlpha(){
        int x;
        readAlpha(x);
        return x;
      }
      template<class T> inline void readInt(T &x){
        x=0;
        bool f=0;
        char c=getc();
        while(!isdigit(c))f^=c=='-',c=getc();
        while(isdigit(c))x=x*10+c-'0',c=getc();
        if(f)x=-x;
      }

  #define __read(T)                             \
      inline void read(T &x) {                  \
        x=0; bool f=0; char c=getc();           \
        while(!isdigit(c))f^=c=='-',c=getc();   \
        while(isdigit(c))x=x*10+c-'0',c=getc(); \
        if(f)x=-x;                              \
      }
      __integer_mapper(__read)
  #undef __read

      inline void read(char &x){x=getc();}
      template<class T=int> inline T read(){
        T x;
        read(x);
        return x;
      }
      template<class T,class... Args> inline void read(T &x,Args &... args){
        read(x),read(args...);
      }

  #define __print(T)           \
      inline void print(T x){  \
        if(x<0)putc('-'),x=-x; \
        if(x>9)print(x/10);    \
        putc('0'+x%10);        \
      }
      __integer_mapper(__print)
  #undef __print

      inline void print(char x){putc(x);}
      inline void print(const char *s){
        int len=strlen(s);
        for(int i=0;i<len;i++)putc(s[i]);
      }
      inline void print(const std::string &s){
        for(int i=0;i<s.length();i++)putc(s[i]);
      }

      template<class T,class... Args> inline void print(const T &x,Args... args){
        print(x),print(args...);
      }
      template<class... Args> inline void println(Args... args){
        print(args...),putchar('\n');
      }
    }
  #endif

  #ifdef MEM_RANDOM
    namespace random{
      const int LuckyNumber=20040725;
      std::mt19937 rng(LuckyNumber^std::chrono::steady_clock::now().time_since_epoch().count());
      std::mt19937_64 rng64(LuckyNumber^std::chrono::steady_clock::now().time_since_epoch().count());

      template<class T> inline T rand(T l,T r){return std::uniform_int_distribution<T>(l,r)(rng);}
      template<class T> inline T rand64(T l,T r){return std::uniform_int_distribution<T>(l,r)(rng);}
    }
  #endif

  #ifdef MEM_MODINT
    namespace modint{
      template<const int mod> struct Z{
        int x;
        inline Z(){x=0;}
        inline Z(int t){x=t;}

        inline void operator-=(Z a){(x-=a.x)<0&&(x+=mod);}
        inline void operator+=(Z a){(x+=a.x)>=mod&&(x-=mod);}
        inline void operator*=(Z a){x=(long long)x*a.x%mod;}

        friend inline Z operator*(Z a,Z b){return (long long)a.x*b.x%mod;}
        friend inline Z operator-(Z a,Z b){return ((a.x-=b.x)<0&&(a.x+=mod)),a;}
        friend inline Z operator+(Z a,Z b){return ((a.x+=b.x)>=mod&&(a.x-=mod)),a;}
      };

      template<const int mod> inline Z<mod> finv(Z<mod> x){
        if(x.x<2)return x;
        return (mod-mod/x.x)*finv(mod%x.x);
      }
      template<const int mod> inline Z<mod> fpow(Z<mod> a,int b){
        Z <mod> s=1;
        for(;b;b>>=1,a=a*a)
          if(b&1)s=s*a;
        return s;
      }

      template<const int mod> inline void init_inverse(int n,Z<mod> *inv){
        inv[0]=inv[1]=1;
        for(int i=2;i<n;i++)inv[i]=(mod-mod/i)*inv[mod%i];
      }
      template<const int mod> inline void init_factorial(int n,Z<mod> *fac,Z<mod> *ifac){
        fac[0]=1,init_inverse(n,ifac);
        for(int i=1;i<n;i++)fac[i]=fac[i-1]*i,ifac[i]=ifac[i-1]*ifac[i];
      }
    }
  #endif

  #ifdef MEM_MATH
    namespace math{
      using std::max;
      using std::min;
      template<class T> inline T abs(T x){return x<0?-x:x;}
      template<class T> inline T gcd(T n,T m){return m?gcd(m,n%m):n;}
      template<class T> inline T lcm(T n,T m){return n/gcd(n,m)*m;}

      template<const stdval::u64 p> struct FastDiv{
        stdval::u64 t,i;
        inline FastDiv():t(stdval::u64(-1)/p),i(mul_inv(p)){}

        inline bool divide(stdval::u64 n){return n*i<=t;}
        inline bool divide(stdval::i64 n){return stdval::u64(n<0?-n:n)*i<=t;}
        inline stdval::u64 mul_inv(stdval::u64 n){
          stdval::u64 x=n;
          for(int i=0;i<5;++i)x*=2-n*x;
          return x;
        }
      };

  #ifdef MEM_INT128
      template<const stdval::u64 b> struct FastMod{
        stdval::u64 m;
        inline FastMod():m(stdval::u64((stdval::u128(1)<<64)/b)){}

        inline stdval::u64 reduce(stdval::u64 a){
          stdval::u64 q=(stdval::u64)((stdval::u128(m)*a)>>64);
          stdval::u64 r=a-q*b;
          return r>=b?r-b:r;
        }
      };
  #endif
    }
  #endif

  #ifdef MEM_CONTAINER
    namespace container{
      using std::pair;
      using std::tuple;
      using std::set;
      using std::unordered_set;
      using std::map;
      using std::unordered_map;

      template<class T> struct vector:std::vector<T>{
        using std::vector<T>::vector;
        vector():std::vector<T>(){}
        vector(const std::vector<T> &plain):std::vector<T>(plain){}

        inline void read(int s=-1){
          if(~s)this->resize(s);
          for(size_t i=0;i<this->size();i++){
            io::read(this->operator[](i));
          }
        }
        inline void print(char pt0=' ',char pt1='\n'){
          for(size_t i=0;i<this->size();i++){
            io::print(this->operator[](i));
            if(i+1<this->size())io::putc(pt0);
          }
          io::putc(pt1);
        }

        inline void sort(){std::sort(this->begin(),this->end());}
        inline void concat(const vector &rhs){this->insert(this->end(),rhs.begin(),rhs.end());}
        inline bool includes(const T &x) const{return std::find(this->begin(),this->end(),x)!=this->end();}

        inline vector slice(int l,int r) const{
          if(l>r)return {};
          if(r<this->size())return vector(this->begin()+l,this->begin()+r);
          vector<int> rsp=(this->begin()+l,this->end());
          return rsp.resize(r-l),rsp;
        }

        inline void from(const std::set<T> &src){
          this->resize(src.size());
          auto it=this->begin();
          for(const T e:src)*it++=e;
        }

        template<class Function> inline void forEach(Function func){for(const auto &it:*this)func(it);}

        template<class R,class Function> inline vector<R> _map(Function func) const{
          vector <R> res(this->size());
          for(size_t i=0;i<this->size();i++)
            res[i]=func(this->operator[](i));
          return res;
        }
        template<class R> inline vector<R> map(R func(T)) const{return this->_map<R>(func);}
        template<class R> inline vector<R> map(const std::function<R(T)> &func) const{return this->_map<R>(func);}
      };
    }
  #endif

  #ifdef MEM_STR
    namespace str {
      using namespace mem::container;

      struct string:std::string{
        using std::string::string;
        string():std::string(""){}
        string(const std::string &plain):std::string(plain){}

  #define __join_declaration(Vector,_)            \
        inline string join(const Vector &) const;
        __string_join_mapper(__join_declaration)
  #undef __join_declaration

        vector<string> split(const string &delim)const{
          if(this->empty())return {};
          char *src=new char[this->length()+1];
          strcpy(src,this->c_str());
          char *tar=new char[delim.length()+1];
          strcpy(tar,delim.c_str());
          vector<string> rsp;
          for(char *pos=strtok(src,tar);pos;pos=strtok(nullptr,tar))
            rsp.push_back(string(pos));
          delete[] src;
          delete[] tar;
          return rsp;
        }

        template<class... Args> static inline string format(const char *fm,Args... args){
          int len=snprintf(nullptr,0,fm,args...);
          char *buf=new char[len+1];
          snprintf(buf,len+1,fm,args...);
          string str(buf);
          delete[] buf;
          return str;
        }
        template<class... Args> static inline string format(const string &fm,Args... args){
          return format(fm.c_str(),args...);
        }
      };

  #define __to_string(T)                   \
      inline string to_string(const T &x){ \
        return std::to_string(x);          \
      }
      __float_mapper(__to_string)
      __integer_mapper(__to_string)
  #undef __to_string
      template<class T> inline string to_string(const vector<T> &vet){return "{"+string(",").join(vet)+"}";}
      template<class T> inline string to_string(const std::vector<T> &vet){return to_string(vector<T>(vet.begin(),vet.end()));}
      template<const int mod> inline string to_string(const mem::modint::Z<mod> &zval){return std::to_string(zval.x);}

  #define __join_instantiation(Vector,to_string)          \
      inline string string::join(const Vector &vet)const{ \
        if(!vet.size())return "";                         \
        string res=to_string(vet[0]);                     \
        for(size_t i=1;i<vet.size();i++){                 \
          res+=*this;                                     \
          res+=to_string(vet[i]);                         \
        }                                                 \
        return res;                                       \
      }
      __string_join_mapper(__join_instantiation)
  #undef __join_instantiation

      inline void print(const str::string &s){
        for(size_t i=0;i<s.length();i++)mem::io::putc(s[i]);
      }

  #define __printfm(T)                                                      \
      template<class... Args> inline void printfm(const T fm,Args... args){ \
        print(str::string().format(fm,args...));                            \
      }
      __string_mapper(__printfm)
  #undef __printfm
    }
  #endif

  #undef __integer_mapper
  #undef __float_mapper
  #undef __string_mapper
  #undef __string_join_mapper

  #ifdef MEM_IO
    using namespace io;
  #endif
  #ifdef MEM_STR
    using namespace str;
  #endif
  #ifdef MEM_MATH
    using namespace math;
  #endif
  #ifdef MEM_UTILS
    using namespace utils;
  #endif
  #ifdef MEM_MODINT
    using namespace modint;
  #endif
  #ifdef MEM_RANDOM
    using namespace random;
  #endif
  #ifdef MEM_STDVAL
    using namespace stdval;
  #endif
  #ifdef MEM_CONTAINER
    using namespace container;
  #endif
}

const int N=5e5+10;
using namespace mem::io;
using namespace mem::container;

int n,m,q,p[N],anc[N];
bool mrk[N],vis[N];
vector<int> ele[N];
pair<vector<int>,int> dat[N];

struct cmp{
public:
  inline bool operator()(const int x,const int y){
    return p[x]<p[y];
  }
};
std::priority_queue<int,std::vector<int>,cmp> f[N],g[N];

struct Edge{
  int u,v;
}e[N];

struct Query{
  int o,x;
}y[N];

int find(int x){
  if(x==anc[x])return x;
  return find(anc[x]);
}

int pop(int k){
  while(f[k].size()&&g[k].size()){
    if(f[k].top()==g[k].top()){
      f[k].pop(),g[k].pop();
    }else{
      int x=f[k].top();
      f[k].pop();
      return x;
    }
  }
  if(f[k].size()){
    int x=f[k].top();
    f[k].pop();
    return x;
  }else{
    return 0;
  }
}

pair<vector<int>,int> merge(int u,int v){
  u=find(u),v=find(v);
  if(u==v)return {{},-1};
  if(ele[u].size()>ele[v].size())std::swap(u,v);
  ele[v].insert(ele[v].end(),ele[u].begin(),ele[u].end());
  anc[u]=v;
  return {ele[u],u};
}

int main(){
#ifdef memset0
  freopen("1.in","r",stdin);
#endif
  read(n,m,q);
  for(int i=1;i<=n;i++)read(p[i]);
  for(int i=1;i<=m;i++)read(e[i].u),read(e[i].v);
  for(int i=1;i<=q;i++){
    read(y[i].o),read(y[i].x);
    if(y[i].o==2)mrk[y[i].x]=true;
  }
  for(int i=1;i<=n;i++){
    anc[i]=i;
    ele[i].push_back(i);
  }
  for(int i=1;i<=m;i++)
    if(!mrk[i]){
      merge(e[i].u,e[i].v);
    }
  for(int i=q;i>=1;i--){
    if(y[i].o==2){
      dat[i]=merge(e[y[i].x].u,e[y[i].x].v);
    }
    // printf("%d : ",i);
    // for(int i=1;i<=n;i++)printf("%d%c",find(i)," \n"[i==n]);
  }
  for(int i=1;i<=n;i++){
    f[find(i)].push(i);
  }
  for(int i=1;i<=q;i++){
    // printf(">> %d %d\n",y[i].o,y[i].x);
    // printf("%d : ",i);
    // for(int i=1;i<=n;i++)printf("%d%c",find(i)," \n"[i==n]);
    if(y[i].o==1){
      int ans=pop(find(y[i].x));
      vis[ans]=true;
      print(p[ans],'\n');
    }else{
      int src=find(e[y[i].x].u);
      for(int x:dat[i].first){
        anc[x]=dat[i].second;
        if(!vis[x]){
          f[dat[i].second].push(x);
          g[src].push(x);
        }
      }
    }
  }
}

#include <bits/stdc++.h>
using namespace std;

#define send {ios_base::sync_with_stdio(false);}
#define help {cin.tie(NULL); cout.tie(NULL);}
#define f first
#define s second
#define getunique(v) {sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end());}
typedef long long ll;
typedef long double lld;
typedef unsigned long long ull;

template<typename A> ostream& operator<<(ostream &cout, vector<A> const &v);
template<typename A, typename B> ostream& operator<<(ostream &cout, pair<A, B> const &p) { return cout << "(" << p.f << ", " << p.s << ")"; }
template<typename A> ostream& operator<<(ostream &cout, vector<A> const &v) {
	cout << "["; for(int i = 0; i < v.size(); i++) {if (i) cout << ", "; cout << v[i];} return cout << "]";
}
template<typename A, typename B> istream& operator>>(istream& cin, pair<A, B> &p) {
	cin >> p.first;
	return cin >> p.second;
}

mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
// mt19937 rng(61378913);
/* usage - just do rng() */

void usaco(string filename) {
  // #pragma message("be careful, freopen may be wrong")
	freopen((filename + ".in").c_str(), "r", stdin);
	freopen((filename + ".out").c_str(), "w", stdout);
}

// #include <atcoder/all>
// using namespace atcoder;

const lld pi = 3.14159265358979323846;
// const ll mod = 1000000007;
// const ll mod = 998244353;
// ll mod;

/* union by size */
struct dsu {
  int n;
  vector<int> sizes, marks;
  vector<vector<int> > graph;

  void init(int rn) {
    n = rn;
    sizes = vector<int>(n);
    fill(sizes.begin(), sizes.end(), 1);
    marks = vector<int>(n);
    for (int i = 0; i < n; i++) marks[i] = i;
    graph = vector<vector<int> >(n);
  }

  void mark(int m, int node) {
    if (marks[node] == m) return;

    marks[node] = m;

    for (int i: graph[node]) mark(m, i);
  }

  void merge(int a, int b) {
    if (marks[a] == marks[b]) return;
    graph[a].push_back(b);
    graph[b].push_back(a);

    if (sizes[marks[a]] > sizes[marks[b]]) swap(a, b);

    sizes[marks[b]] += sizes[marks[a]];
    sizes[marks[a]] = 0;
    mark(marks[b], a);
  }

  int find(int n) { return marks[n]; }
};

ll n, m, k, q, l, r, x, y, z;
const ll template_array_size = 1e6 + 1600;
int a[template_array_size];
ll b[template_array_size];
ll c[template_array_size];
string s, t;
ll ans = 0;

bool rem[500005];
int comp[500005];
pair<int, int> ed[500005];
pair<int, int> qv[500005];
set<ll> vals[500005];
pair<int, int> targ[500005];
vector<pair<int, int>> edges[500005];
dsu d;
vector<ll> kill;

void relabel(int v, int compv) {
	if (a[v] != 0) {
		kill.push_back(a[v] * n + v);
		vals[comp[v]].erase(a[v] * n + v);
		comp[v] = compv;
	}
	comp[v] = compv;

	for (pair<int, int> x: edges[v]) {
		if (!rem[x.s] && comp[x.f] != compv) {
			relabel(x.f, compv);
		}
	}
}

void solve(int tc = 0) {
	cin >> n >> m >> q;

	for (int i = 0; i < n; i++) cin >> a[i];

	for (int i = 0; i < m; i++) {
		cin >> ed[i];
		--ed[i].f;
		--ed[i].s;
	}

	memset(rem, 0, sizeof(rem));

	for (int i = 0; i < q; i++) {
		cin >> qv[i];
		--qv[i].s;
		if (qv[i].f == 2) rem[qv[i].s] = 1;
	}

	d.init(n);

	for (int i = 0; i < m; i++) {
		if (!rem[i]) d.merge(ed[i].f, ed[i].s);
	}

	for (int i = q - 1; i >= 0; i--) {
		if (qv[i].f == 2) {
			pair<ll, ll> e = ed[qv[i].s];
			if (d.marks[e.f] == d.marks[e.s]) targ[i].f = -1;
			else {
				if (d.sizes[d.marks[e.f]] > d.sizes[d.marks[e.s]]) swap(e.f, e.s);
				targ[i] = e;
				d.merge(e.f, e.s);
			}
		}
	}

	for (int i = 0; i < n; i++) {
		comp[i] = d.marks[i];

		vals[comp[i]].insert(a[i] * n + i);
	}

	memset(rem, 0, sizeof(rem));

	for (int i = 0; i < m; i++) {
		edges[ed[i].f].push_back(make_pair(ed[i].s, i));
		edges[ed[i].s].push_back(make_pair(ed[i].f, i));
	}

	int comp_val = n;

	for (int i = 0; i < q; i++) {
		if (qv[i].f == 1) {
			if (!vals[comp[qv[i].s]].size()) cout << 0 << '\n';
			else {
				// cout << qv[i].s << " " << comp[qv[i].s] << '\n';
				auto it = --vals[comp[qv[i].s]].end();
				cout << *it / n << '\n';
				a[*it % n] = 0;
				vals[comp[qv[i].s]].erase(it);
			}

			// for (ll i = 0; i < n; i++) cout << comp[i] << " ";
			// cout << '\n';
		} else {
			rem[qv[i].s] = 1;
			if (targ[i].f != -1) {
				kill.clear();
				relabel(targ[i].f, comp_val);
				sort(kill.begin(), kill.end());
				for (ll x: kill) vals[comp_val].insert(vals[comp_val].end(), x);

				++comp_val;
			}
		}
	}
}

int main() {
	#ifdef galen_colin_local
		auto begin = std::chrono::high_resolution_clock::now();
	#endif

	send help

	#ifndef galen_colin_local
		// usaco("moop");
	#endif

	// usaco("cowland");

	// freopen("tc.cpp", "r", stdin);

	int tc = 1;
	// cin >> tc;
	for (int t = 0; t < tc; t++) solve(t);

	#ifdef galen_colin_local
		auto end = std::chrono::high_resolution_clock::now();
		cout << setprecision(4) << fixed;
		// cout << "Execution time: " << std::chrono::duration_cast<std::chrono::duration<double>>(end - begin).count() << " seconds" << endl;
	#endif
}

// C++ 17
#include <bits/stdc++.h>
using namespace std;using pr = pair<int, int>;int N, M, Q, A[200005], par[200005];pr E[300005], QS[500005];bool chk[300005];set<int> s[200005];stack<pr> st;
int f(int x) { return par[x] = (par[x] == x ? x : f(par[x])); }
void uni(int x, int y) {x = f(x), y = f(y);if(x == y) return;if(s[x].size() > s[y].size()) swap(x, y);st.push(pr(x, y));for(auto it : s[x]) s[y].insert(it);par[x] = y;}
int main() {ios::sync_with_stdio(0), cin.tie(0);cin >> N >> M >> Q;iota(par, par + N + 1, 0);
	for(int i=1; i<=N; i++) cin >> A[i], s[i].insert(A[i]);
	for(int i=1, x, y; i<=M; i++) {cin >> x >> y;E[i] = pr(x, y);}
	for(int i=1, x, y; i<=Q; i++) {cin >> x >> y;QS[i] = pr(x, y);if(x == 2) chk[y] = 1;}
	for(int i=1; i<=M; i++) if(!chk[i]) uni(E[i].first, E[i].second);
	for(int i=Q; i; i--) {
		if(QS[i].first == 1)QS[i].second = f(QS[i].second);
		 else {int x = E[QS[i].second].first, y = E[QS[i].second].second;if(f(x) == f(y))QS[i].first = 0;else uni(x, y);}}
	for(int i=1; i<=Q; i++) {
		if(QS[i].first == 1) {int p = QS[i].second;int ans = 0;if(s[p].size() > 0) {ans = *s[p].rbegin();s[p].erase(ans);}cout << ans << "\n";
		} else if(QS[i].first == 2) {
			int x = st.top().first, y = st.top().second; st.pop();set<int> tmp;
			for(auto it : s[x]) if(s[y].find(it) != s[y].end()) {tmp.insert(it);s[y].erase(it);}s[x] = tmp;}}}

#include <bits/stdc++.h>
#define ld long double
#define endl "\n"
#define fastio ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define pb push_back
#define mp(a,b) make_pair(a,b)
#define ms(v,x) memset(v,x,sizeof(v))
#define all(v) v.begin(),v.end()
#define ff first
#define ss second
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define per(i, a, b) for(int i = b-1; i>=a ; i--)
#define trav(a, x) for(auto& a : x)
#define allin(a , x) for(auto a : x)
#define Unique(v) sort(all(v));v.erase(unique(all(v)),v.end());
#define sz(v) ((int)v.size())
//#define int long long
using namespace std;
typedef vector<int> vi;
#define y1 abacaba
#define left sefude
#define db(x) cerr <<#x <<" == "<<x << endl;
#define db2(x,y) cerr<<#x <<" == "<<x<<", "<<#y<<" == "<<y<<endl;
#define db3(x,y,z) cerr << #x<<" == "<<x<<", "<<#y<<" == "<<y<<", "<<#z<<" == "<<z<<endl;
#define prl cerr<<"called: "<< __LINE__ << endl;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
inline ll mod(ll n, ll m ){ ll ret = n%m; if(ret < 0) ret += m; return ret; }
ll gcd(ll a, ll b){return (b == 0LL ? a : gcd(b, a%b));}
ll exp(ll a,ll b,ll m){
    if(b==0LL) return 1LL;
    if(b==1LL) return mod(a,m);
    ll k = mod(exp(a,b/2,m),m);
    if(b&1LL){
        return mod(a*mod(k*k,m),m);
    }
    else return mod(k*k,m);
}

const int N = 200100;
int p[N];
pii e[300100],Q[500100];
bool mark[300100];
vi vec[200100];
vi here[300100];
set<pii> vals[N];
int pai[N];
bool sp[300100];
int tam(int x){return sz(vec[pai[x]]);}
void join(int a,int b){
  a=pai[a],b=pai[b];
  if(a==b)return;
  if(tam(a)>tam(b))swap(a,b);
  for(int x : vec[a]){
    vec[b].pb(x);
    pai[x] = b;
  }
  vec[a].clear();
}

inline int maxi(int x){
  x = pai[x];
  pii v = *vals[x].rbegin();
  vals[x].erase(v);
  p[v.ss]=0;
  vals[x].insert(pii(p[v.ss],v.ss));
  return v.ff;
}

// #define DB  0
inline void erase(int a,int b,int id){
  b=pai[b];
  for(int x : here[id]){
    pai[x] = a;
    vals[b].erase(pii(p[x],x));
    vals[a].insert(pii(p[x],x));
  }
}
int32_t main(){
  fastio;
  int n,m,q;
  cin>>n>>m>>q;
  for(int i=1;i<=n;i++){
    cin>>p[i];
    pai[i]=i;
    vec[i].pb(i);
  }
  for(int i=1;i<=m;i++)cin>>e[i].ff>>e[i].ss;
  for(int i=1;i<=q;i++){
    cin >> Q[i].ff>>Q[i].ss;
    if(Q[i].ff==2){
      mark[Q[i].ss]=1;
    }
  }
  for(int i=1;i<=m;i++){
    if(!mark[i]){
      join(e[i].ff,e[i].ss);
    //  if(DB)cout <<"join "<<i<<endl;
    }
  }
  for(int i=q;i>=1;i--){
    if(Q[i].ff==2){
      int id = Q[i].ss;
      if(pai[e[id].ff]!=pai[e[id].ss]){
    //    if(DB)cout <<"oi "<<id<<endl;
        sp[id]=1;
        if(tam(e[id].ff)>tam(e[id].ss)){
          swap(e[id].ff,e[id].ss);
        }
        e[id].ff = pai[e[id].ff];
        here[id] = vec[e[id].ff];
        e[id].ss = pai[e[id].ss];
        join(e[id].ff,e[id].ss);
      }
    }
  }
  for(int i=1;i<=n;i++){
    if(pai[i]==i){
      for(int x : vec[i])
        vals[i].insert(pii(p[x],x));
    }
  }

  for(int i=1;i<=q;i++){
    if(Q[i].ff == 1){
      cout << maxi(Q[i].ss) << endl;
    }else{
      int id = Q[i].ss;
      if(!sp[id])continue;
    //  if(DB)cout << "remove "<<id<<endl;
      erase(e[id].ff,e[id].ss,id);
    }
  }

  // math -> gcd it all
  // Did u check N=1? Did you switch N,M?
}

#pragma GCC optimize("Ofast")

#include <bits/stdc++.h>
using namespace std;

#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pop_b pop_back
#define pf push_front
#define pop_f pop_front
#define mt make_tuple
#define eb emplace_back
#define sf(x) sizeof(x)
#define len(x) x.length()
#define sz(x) x.size()
#define fastio() ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)

#define LB(x,v) (lower_bound(x.begin(),x.end(),v)-x.begin())
#define UB(x,v) (upper_bound(x.begin(),x.end(),v)-x.begin())
typedef long long ll;
typedef pair<ll,ll> ii;
typedef pair<int, int> pii;
typedef long double ld;
typedef vector<int> vi;
typedef vector<set<ll>> vset;
typedef vector<ll> vl;
typedef vector<ld> vd;
typedef deque<ll> dql;
typedef deque<int> dqi;
typedef unsigned long long ull;
typedef tuple<int,int,int> State;

#define error(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }
void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {
	cerr << *it << " = " << a << ", ";
	err(++it, args...);
	cout<<"\n";
}

#define vmax(type)   std::numeric_limits<type>::max()
#define vmin(type)   std::numeric_limits<type>::min()
#define each(a,x) for( auto &a:(x))
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define repr(i, n) for (ll i = (n) - 1; i >= 0; i--)
#define rep2(i, l, r) for (ll i = (l); i < (r); i++)
#define rep2r(i, l, r) for (ll i = (r) - 1; i >= (l); i--)
#define range(a) a.begin(), a.end()
#define deb(x) cout<<#x<<" "<<x<<endl;
#define cinai(a, n) vi a(n); rep(i, n) { cin>>a[i]; }
#define cinal(a, n) vl a(n); rep(i, n) { cin>>a[i]; }
#define coutai(a, n) rep(i, n) { cout<<a[i]<<" "; } ent;
#define coutal(a, n) rep(i, n) { cout<<a[i]<<" "; } ent;
#define ent cout<<endl;
#define resize_vec(a) a.resize(unique(a.begin(), a.end()) - a.begin());
#define ms(dp, x) memset(dp, x, sf(dp))
#define endl '\n'

ll powm(ll a, ll b, ll mod) {
	ll res=1;
	while(b) {
		if(b&1)
			res=(res*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return res;
}

const ll mod = 1e9 + 7;
const ll N = 1000005;
const ll inf = 1e9;

int n, tin[N], tout[N];
int q, par[N], timer = 0, m, arr[N];
vi adj[N];
bool del[N];
pair<int, int> t[N<<2], query[N], edg[N];

int findPar(int x){
	if(x == par[x])
		return x;
	return par[x] = findPar(par[x]);
}

void unite(int a, int b){
	a = findPar(a);
	b = findPar(b);

	if(a == b)
		return;
	++n;
	par[a] = n;
	par[n] = n;
	par[b] = n;
	adj[n].pb(a);
	adj[n].pb(b);
}

void dfs(int v){
	tin[v] = ++timer;
	for(int to : adj[v])
		dfs(to);
	tout[v] = timer;
}

pii segMax(int v, int tl, int tr, int l, int r) {
	if (l > r || tl > r || tr < l) {
    	return mp(0, 0);
  	}

  	if (l <= tl && tr <= r) {
    	return t[v];
  	}

  	int mid = (tl + tr) >> 1;
  	int c1 = (v << 1), c2 = (c1 | 1);

  	return max(segMax(c1, tl, mid, l, r), segMax(c2, mid + 1, tr, l, r));
}

void update(int v, int tl, int tr, int p, pii x) {
  	if (tl == tr) {
    	t[v] = x;
    	return;
  	}

  	int mid = (tl + tr) >> 1;
	int c1 = (v << 1), c2 = (c1 | 1);

  	if (p <= mid) {
    	update(c1, tl, mid, p, x);
  	}
  	else {
    	update(c2, mid + 1, tr, p, x);
  	}

  	t[v] = max(t[c1], t[c2]);
}

void solve()
{
	cin >> n >> m >> q;

	for(int i = 1; i <= n; i++)
		cin >> arr[i];

	for(int i = 1; i <= m; i++){
		del[i] = 0;
		cin >> edg[i].fi >> edg[i].se;
	}

	for(int i = 1; i <= q; i++){
		cin >> query[i].fi >> query[i].se;
		if(query[i].fi == 2)
			del[query[i].se] = 1;
	}

	for(int i = 1; i <= n; i++)
		par[i] = i;

	for(int i = 1; i <= m; i++){
		if(!del[i])
			unite(edg[i].fi, edg[i].se);
	}

	for(int i = q; i >= 1; i--){
		if(query[i].fi == 2){
			unite(edg[query[i].se].fi, edg[query[i].se].se);
		}else{
			query[i].se = findPar(query[i].se);
		}
	}

	for(int i = n; i >= 1; i--)
		if(par[i] == i)
			dfs(i);

	for(int i = 1; i <= n; i++){
		update(1, 1, n, tin[i], mp(arr[i], tin[i]));
	}

	for(int i = 1; i <= q; i++){
		int tp = query[i].fi;

		if(tp == 1){
			int v = query[i].se;
			pii tmp = segMax(1, 1, n, tin[v], tout[v]);

			if(tmp.fi == 0)
				cout<<0<<endl;
			else{
				cout<<tmp.fi<<endl;
				update(1, 1, n, tmp.se, mp(0, 0));
			}
		}
	}
}

signed main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	cout << fixed << setprecision(15);

	int tc = 1;
	// cin>>tc;
	while(tc--)
	{
		solve();
	}
	return 0;
}

#include <bits/stdc++.h>
#define For(i, l, r) for (int i = l; i <= r; i++)
#define Down(i, r, l) for(int i = r; i >= l; i--)
#define mk make_pair
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
template<typename T> inline void ckmax(T& x, T y) { x = (y > x ? y : x); }
template<typename T> inline void ckmin(T& x, T y) { x = (y < x ? y : x); }

inline int read() {
  char ch = getchar();
  int s = 0, f = 1;
  while (ch < '0' || ch > '9') {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while ('0' <= ch && ch <= '9') {
    s = s * 10 + ch - '0';
    ch = getchar();
  }
  return f * s;
}
const int maxn = 2e5 + 7;
const int maxm = 3e5 + 7;
const int maxq = 5e5 + 7;
int p[maxn], tim[maxq];
struct edge{
    int next, to;
}e[maxn*2];
int cnt1 = 0;
int tree[maxn*2];
inline int makeNode(int t = 0){
    ++cnt1;
    tree[cnt1] = t;
    return cnt1;
}
struct node{
    int u, v;
}tmpEdge[maxm],sortEdge[maxm];
struct que{
    int opt;
    int index;
}query[maxq];

int cnt = 0;
int head[maxn * 2];
bool initEdge[maxm];
inline void addEdge(int u, int v){
    e[++cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt;
}

int fa[maxn * 2];
int getFa(int u){
    if (fa[u] == u) return u;
    else return fa[u]= getFa(fa[u]);
}
const int LOG = 18;
int anc[maxn*2][LOG + 1];
int mi_dfn[maxn*2], mx_dfn[maxn*2], rev[maxn*2];
int dfns = 0;

void dfs(int u){
    For(i, 1, LOG) anc[u][i] = anc[anc[u][i - 1]][i - 1];
    bool isLeaf = 1;
    mi_dfn[u] = maxq;
    for(int i = head[u]; i; i = e[i].next){
        int v= e[i].to;
        isLeaf = 0;
        anc[v][0] = u;
        dfs(v);
        mi_dfn[u] = min(mi_dfn[u], mi_dfn[v]);
        mx_dfn[u] = max(mx_dfn[u], mx_dfn[v]);
    }
    if (isLeaf){
        rev[++dfns] = u;
        mi_dfn[u] = mx_dfn[u] = dfns;
    }
}
int mx[maxn * 4 + 5], mx_pos[maxn * 4 + 5];
	void push_up(int p) {
		if(mx[p << 1] > mx[p << 1 | 1]) {
			mx[p] = mx[p << 1];
			mx_pos[p] = mx_pos[p << 1];
		} else {
			mx[p] = mx[p << 1 | 1];
			mx_pos[p] = mx_pos[p << 1 | 1];
		}
	}
	void build(int P, int l, int r) {
		if(l == r) {
			mx[P] = p[rev[l]];
			mx_pos[P] = l;
			return;
		}
		int mid = (l + r) >> 1;
		build(P << 1, l, mid);
		build(P << 1 | 1, mid + 1, r);
		push_up(P);
	}
	void point_modify(int p, int l, int r, int pos) {
		if(l == r) {
			mx[p] = 0;
			return;
		}
		int mid = (l + r) >> 1;
		if(pos <= mid) {
			point_modify(p << 1, l, mid, pos);
		} else {
			point_modify(p << 1 | 1, mid + 1, r, pos);
		}
		push_up(p);
	}
	pii quer(int p, int l, int r, int ql, int qr) {
		if(ql <= l && qr >= r) {
			return make_pair(mx[p], mx_pos[p]);
		}
		int mid = (l + r) >> 1;
		pii res = mk(0, 0);
		if(ql <= mid) {
			res = quer(p << 1, l, mid, ql, qr);
		}
		if(qr > mid) {
			ckmax(res, quer(p << 1 | 1, mid + 1, r, ql, qr));
		}
		return res;
	}

int getAnc(int u, int t){
    Down(i, LOG, 0){
        if (anc[u][i] && tree[anc[u][i]] <= t){
            u = anc[u][i];
        }
    }
    return u;
}

int main(){
    int n = read();
    int m = read(), q = read();
    For(i, 1, n){
        p[i] = read();
        makeNode();
    }

    For(i, 1 , m){
        tmpEdge[i].u = read();
        tmpEdge[i].v = read();
        initEdge[i] = 1;
    }

    For(i, 1, q){
        query[i].opt = read();
        query[i].index = read();
        if (query[i].opt == 2) initEdge[query[i].index] = 0;
    }

    For(i, 1 ,2*n) fa[i] = i;
    int m1 = 0;
    For(i, 1, m){if (initEdge[i]){sortEdge[++m1] = tmpEdge[i];}}
    Down(i, q, 1){
        if (query[i].opt == 2){
            sortEdge[++m1] = tmpEdge[query[i].index];
        }
        else tim[i] = m1;
    }

    For(i, 1, m1){
        int u = getFa(sortEdge[i].u);
        int v = getFa(sortEdge[i].v);
        if (u == v) continue;
        makeNode(i);
        addEdge(cnt1, u);
        addEdge(cnt1, v);
        fa[u] = fa[v] = cnt1;
    }
    For(i, 1, cnt1){
        if (getFa(i) == (i)) dfs(i);
    }
    build(1, 1,n);
    For(i, 1, q){
        if (query[i].opt == 1){
            int u = query[i].index;
            int v = getAnc(u, tim[i]);
            pii qres = quer(1, 1, n, mi_dfn[v], mx_dfn[v]);
            printf("%d\n", qres.first);
            point_modify(1, 1, n, qres.second);
        }
    }
    return 0;
}

#include "bits/stdc++.h"

using namespace std;

#define _ ios_base::sync_with_stdio(0);cin.tie(0);
#define endl '\n'
#define debug(x) cerr << #x << " == " << (x) << '\n';
#define all(X) (X).begin(), (X).end()
#define sz(X) (int)X.size()

using ll = long long;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3fLL;

int main()
{ _
    int n, m, q; cin >> n >> m >> q;

    static vector p(n, 0);
    for (auto& x : p) cin >> x;

    vector e(m, pair(0, 0));
    for (auto& [u, v] : e)
    {
        cin >> u >> v; --u, --v;
    }

    vector skip(m, 0);
    vector Q(q, pair(0, 0));
    for (auto& [t, x] : Q)
    {
        cin >> t >> x; --x;
        if (t == 2) skip[x] = 1;
    }

    struct Data
    {
        int v;
        bool operator<(const Data& rhs) const
        {
            return pair(p[v], v) > pair(p[rhs.v], rhs.v);
        }
    };

    auto update = [&](set<Data>& S)
    {
        set<Data> R(S.begin(), S.end());
        swap(S, R);
    };

    vector parent(n, 0); iota(all(parent), 0);
    vector S(n, set<Data>());
    for (int u = 0; u < n; ++u)
        S[u].insert(Data{u});

    auto unite = [&](int u, int v)
    {
        while (u != parent[u]) u = parent[u];
        while (v != parent[v]) v = parent[v];
        if (u != v)
        {
            if (sz(S[u]) < sz(S[v])) swap(u, v);
            parent[v] = u;
            for (auto x : S[v]) S[u].insert(x);
            return v;
        }
        return -1;
    };

    for (int j = 0; j < m; ++j)
    {
        if (skip[j]) continue;
        unite(e[j].first, e[j].second);
    }

    vector child(m, -1);
    for (int z = q - 1; z >= 0; --z)
    {
        auto [t, j] = Q[z];
        if (t == 2) child[j] = unite(e[j].first, e[j].second);
    }

    auto split = [&](int j)
    {
        int v = child[j], u = parent[v];
        assert(u == parent[u]);
        for (auto x : S[v]) S[u].erase(x);
        update(S[v]);
        parent[v] = v;
    };

    for (auto [t, x] : Q)
    {
        if (t == 1)
        {
            while(x != parent[x]) x = parent[x];
            int v = S[x].begin()->v;
            cout << p[v] << endl;
            S[x].erase(S[x].begin());
            p[v] = 0;
            S[x].insert(Data{v});
        }
        else if (child[x] != -1) split(x);
    }

    exit(0);
}

#include <bits/stdc++.h>
#define F(i,j,k) for(int i=(j);i<=(k);++i)
#define D(i,j,k) for(int i=(j);i>=(k);--i)
#define rep(it,s) for(__typeof(s.begin()) it=s.begin();it!=s.end();++it)
#define Rep(a,s) for(auto a:s)
#define PB push_back
#define MP make_pair
#define FF first
#define SS second
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
template<class Type>ll quick_pow(Type x,Type y,Type Mod){
    ll res=1;
    while(y){
        if(y&1)res=res*x%Mod;
        x=x*x%Mod,y>>=1;
    }
    return res;
}
template<class Type>ll inv(Type x,Type Mod){return quick(x,Mod-2,Mod);}
namespace IO{
    template <class T>
    inline void read(T &x){
        x=0;int f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
        x*=f;
    }
};
using namespace IO;
const int N=1000005;
struct Edge{
    int u,v;
}e[N];
int n,m,Q,p[N],pos[N],fa[N],flag[N],opt[N],key[N],vcnt,id[N];
int ask[N],top;
vector<int>E[N];
inline void add(int x,int y){E[x].PB(y);}
int find(int x){
    return fa[x]=(fa[x]==x?x:find(fa[x]));
}
void uni(int x,int y){
    int fx=find(x),fy=find(y);
    if(fx!=fy)fa[fx]=fy;
}
void Merge(int x,int y){
    int fx=find(x),fy=find(y);
    if(fx==fy)return ;
    ++vcnt;
    uni(fx,vcnt),uni(fy,vcnt);
    add(vcnt,fx),add(vcnt,fy);
}
int dfn,Begin[N],End[N],size[N];
void dfs(int x){
    Begin[x]=++dfn,id[dfn]=x;
    size[x]=1;
    Rep(y,E[x]){
        dfs(y);
        size[x]+=size[y];
    }
    End[x]=Begin[x]+size[x]-1;
}
struct SegmentTree{
    int L,R,Mx;
}t[N<<1];
void pushup(int Pos){
    t[Pos].Mx=max(t[Pos<<1].Mx,t[Pos<<1|1].Mx);
}
void build(int Pos,int L,int R){
    t[Pos].L=L,t[Pos].R=R;
    if(L==R){
        t[Pos].Mx=p[id[L]];
        return ;
    }
    int mid=(L+R)>>1;
    build(Pos<<1,L,mid),build(Pos<<1|1,mid+1,R);
    pushup(Pos);
}
int query(int Pos,int L,int R){
    if(L<=t[Pos].L&&t[Pos].R<=R)return t[Pos].Mx;
    if(t[Pos].L>R||t[Pos].R<L)return 0;
    return max(query(Pos<<1,L,R),query(Pos<<1|1,L,R));
}
void modify(int Pos,int x,int delta){
    if(t[Pos].L>x||t[Pos].R<x)return ;
    if(t[Pos].L==t[Pos].R){
        t[Pos].Mx=delta;
        return ;
    }
    modify(Pos<<1,x,delta),modify(Pos<<1|1,x,delta);
    pushup(Pos);
}
int main(){
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    read(n),read(m),read(Q);
    vcnt=n;
    F(i,1,n)read(p[i]),pos[p[i]]=i;
    F(i,1,m){
        read(e[i].u),read(e[i].v);
    }
    F(i,1,Q){
        read(opt[i]),read(key[i]);
        if(opt[i]==2)flag[key[i]]=1;
    }
    F(i,1,n*2)fa[i]=i;
    F(i,1,m)if(!flag[i]){
        Merge(e[i].u,e[i].v);
    }
    D(i,Q,1){
        if(opt[i]==2)Merge(e[key[i]].u,e[key[i]].v);
        else ask[++top]=find(key[i]);
    }
    F(i,1,vcnt)if(fa[i]==i)dfs(i);
    build(1,1,vcnt);
    D(i,top,1){
        int temp=query(1,Begin[ask[i]],End[ask[i]]);
        printf("%d\n",temp);
        if(temp){
            modify(1,Begin[pos[temp]],0);
        }
    }
    return 0;
}

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct Tree
{
	#define lc x<<1
	#define rc x<<1|1
	#define mid ((l+r)>>1)
	int maxp[1600005],a[400005];
	void pushup(int x)
	{
		maxp[x]=a[maxp[lc]]>a[maxp[rc]]?maxp[lc]:maxp[rc];
	}
	void build(int x,int l,int r)
	{
		if(l==r)
		{
			maxp[x]=l;
			return;
		}
		build(lc,l,mid);
		build(rc,mid+1,r);
		pushup(x);
	}
	int ask(int x,int l,int r,int from,int to)
	{
		if(l>=from&&r<=to)return maxp[x];
		int ans=from;
		if(from<=mid)
		{
			int p=ask(lc,l,mid,from,to);
			if(a[p]>=a[ans])ans=p;
		}
		if(to>mid)
		{
			int p=ask(rc,mid+1,r,from,to);
			if(a[p]>=a[ans])ans=p;
		}
		return ans;
	}
	void update(int x,int l,int r,int p)
	{
		if(l==r)
		{
			a[l]=0;
			return;
		}
		if(p<=mid)update(lc,l,mid,p);
		else update(rc,mid+1,r,p);
		pushup(x);
	}
}T;
struct Edge
{
	int u,v;
	int t;
}e[300005];
struct Query
{
	int type;
	int k;
}a[500005];
int n,m,q,tot,p[400005],t[400005],r[400005],pa[400005],anc[20][400005];
int child[400005][2];
bool cmp(Edge a,Edge b)
{
	return a.t>b.t;
}
int find(int x)
{
	return x==r[x]?x:r[x]=find(r[x]);
}
int ind,dfn[400005],size[400005];
void dfs(int node)
{
	dfn[node]=++ind;
	T.a[ind]=p[node];
	size[node]=1;
	if(child[node][0])dfs(child[node][0]);
	if(child[node][1])dfs(child[node][1]);
	size[node]+=size[child[node][0]]+size[child[node][1]];
}
void pre()
{
	for(int i=1;i<=tot;i++)anc[0][i]=pa[i];
	for(int i=1;i<20;i++)
	  for(int j=1;j<=tot;j++)
	    anc[i][j]=anc[i-1][anc[i-1][j]];
}
void ask(int node,int ti)
{
	for(int i=19;i>=0;i--)
	  if(t[anc[i][node]]>ti)
	    node=anc[i][node];
	int pos=T.ask(1,1,tot,dfn[node],dfn[node]+size[node]-1);
	printf("%d\n",T.a[pos]);
	T.update(1,1,tot,pos);
}
int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)scanf("%d",&p[i]);
	for(int i=1;i<=m;i++)scanf("%d%d",&e[i].u,&e[i].v),e[i].t=q+1;
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&a[i].type,&a[i].k);
		if(a[i].type==2)e[a[i].k].t=i;
	}
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=n;i++)r[i]=i,t[i]=q+1;
	tot=n;
	for(int i=1;i<=m;i++)
	{
		int u=e[i].u,v=e[i].v;
		if(find(u)==find(v))continue;
		pa[find(u)]=pa[find(v)]=++tot;
		child[tot][0]=find(u);
		child[tot][1]=find(v);
		r[tot]=r[find(u)]=r[find(v)]=tot;
		t[tot]=e[i].t;
	}
	for(int i=tot;i>=1;i--)
		if(!dfn[i])dfs(i);
	pre();
	T.build(1,1,tot);
	for(int i=1;i<=q;i++)
	{
		if(a[i].type==1)
		  ask(a[i].k,i);
	}
	return 0;
}

#include <bits/stdc++.h>
//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>
#define sz(x) int(x.size())
#define all(x) x.begin(),x.end()
#define PB push_back
#define MP make_pair
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pil pair<int, ll>
#define pli pair<ll, int>
#define pdd pair<ld, ld>
#define ft first
#define sd second
#define i2 array<int,2>
#define i3 array<int,3>
#define l2 array<ll,2>
using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
template<class T>
using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
const int N = 200100;
const int BIG_N = 400100;
const int M = 300100;
const int Q = 500100;
const int BIG = int(5e8) + 10;
const int oo = 2e9;
const ll OO = 1e18;
const int md = 998244353;
const int PW = 30;
const ld E = 1e-9;
const int MX = (1 << 20);
vector<int> g[BIG_N];
int n, p[BIG_N], U[M], V[M], pre[BIG_N], a[BIG_N];
int m, q, tp[Q], vl[Q], lst, tin[BIG_N], tout[BIG_N], tt = 0, mem_ver[Q];
i2 st[4 * BIG_N];
bool mrk[M], used[BIG_N];

mt19937 rnd(chrono::system_clock().now().time_since_epoch().count());

void BAD(){
    cout << -1;
    exit(0);
}

int get(int x) { return (pre[x] == x ? x : pre[x] = get(pre[x])); }

void dfs(int v){
    a[tt] = p[v];
    tin[v] = tt++;

    for (int u : g[v])
        dfs(u);

    tout[v] = tt - 1;
}

void build(int v, int l, int r){
    if (l == r){
        st[v] = {a[l], l};
        return;
    }

    int md = (l + r) >> 1;

    build(v + v, l, md);
    build(v + v + 1, md + 1, r);

    st[v] = max(st[v + v], st[v + v + 1]);
}

i2 get(int v, int tl, int tr, int l, int r){
    if (l > r) return {-oo, 0};

    if (tl == l && tr == r) return st[v];

    int md = (tl + tr) >> 1;

    return max(get(v + v, tl, md, l, min(r, md)),
               get(v + v + 1, md + 1, tr, max(md + 1, l), r));
}

void update(int v, int l, int r, int ps){
    if (l == r){
        st[v] = {0, l};
        return;
    }

    int md = (l + r) >> 1;

    if (ps <= md)
        update(v + v, l, md, ps);
    else update(v + v + 1, md + 1, r, ps);

    st[v] = max(st[v + v], st[v + v + 1]);
}

int main() {
#ifdef _LOCAL
    freopen("in.txt","r",stdin); // freopen("output.txt","w",stdout);
#else
//    freopen("mining.in","r",stdin); freopen("mining.out","w",stdout);
    ios_base::sync_with_stdio(0); cin.tie(0);
#endif

    cin >> n >> m >> q;

    for (int i = 1; i <= n; i++)
        cin >> p[i];

    for (int i = 1; i <= m; i++){
        cin >> U[i] >> V[i];
    }

    for (int i = 1; i <= q; i++){
        cin >> tp[i] >> vl[i];

        if (tp[i] == 2)
            mrk[vl[i]] = 1;
    }

    for (int i = 1; i < BIG_N; i++){
        pre[i] = i;
    }

    lst = n;

    for (int i = 1; i <= m; i++)
        if (!mrk[i]){
            int xx = get(U[i]), yy = get(V[i]);

            if (xx == yy) continue;

            lst++;

            g[lst].PB(xx);
            g[lst].PB(yy);

            pre[xx] = lst;
            pre[yy] = lst;
        }

    for (int it = q; it > 0; it--){
        if (tp[it] == 1){
            mem_ver[it] = get(vl[it]);
            continue;
        }

        mrk[vl[it]] = 0;

        int i = vl[it];

        int xx = get(U[i]), yy = get(V[i]);

        if (xx == yy) continue;

        lst++;

        g[lst].PB(xx);
        g[lst].PB(yy);

        pre[xx] = lst;
        pre[yy] = lst;
    }

    lst++;

    for (int i = 1; i <= n; i++){
        if (used[get(i)]) continue;

        used[get(i)] = 1;

        g[lst].PB(get(i));
    }

    dfs(lst);

    build(1, 0, lst - 1);

    for (int it = 1; it <= q; it++)
        if (tp[it] == 1){
            int v = mem_ver[it];

            i2 res = get(1, 0, lst - 1, tin[v], tout[v]);

            cout << res[0] << '\n';

            update(1, 0, lst - 1, res[1]);
        }

    return 0;
}

#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define f first
#define s second
using namespace std;
const int mxn=2e5+5;
const int mxm=3e5+5;
const int mxq=5e5+5;

const int inf=1e9;
int p[mxn];
int L[mxm],R[mxm];
bool usd[mxm];
int tp[mxq],id[mxq];

struct reachability_tree {
	int parent[mxn];
	int sz[mxn];
	int in[mxn],out[mxn],id[mxn];
	int pc[mxn];
	vector<int> g[mxn];
	vector<int> w[mxn];
	int T=0;

	void init(int n) {
		for(int i=1;i<=n;i++) {
			parent[i] = i;
			sz[i] = 1;
		}
	}

	int findrep(int u) {
		return parent[u] == u ? u : findrep(parent[u]);
	}

	void unite(int u,int v,int cst) {
		u=findrep(u);
		v=findrep(v);
		if(u == v) return;

		if(sz[u] > sz[v]) swap(u,v);

		parent[u] = v;
		sz[v] += sz[u];
		g[v].push_back(u);
		w[v].push_back(cst);
		pc[u] = cst;

	}
	void dfs(int u) {
		in[u] = ++T;
		id[T] = u;
		for(int v : g[u]) {
			dfs(v);
		}
		out[u] = T;
	}

	pii range(int u, int tm) {
		while(parent[u] != u && pc[u] >= tm) u = parent[u];

		int p = upper_bound(w[u].begin(),w[u].end(),tm,[](int a,int b) {
			return a > b;
		}) - w[u].begin();

		if(p == 0) {
			return {in[u], in[u]};
		}

		int v = g[u][p-1];
		return {in[u],out[v]};
	}

} rt ;

struct segtree {
	pii tree[4*mxn];

	void update(int node,int b,int e,int p,int v) {
		if(e<p || b>p) return;
		if(b == e) {
			tree[node] = {v,b};
			return;
		}

		int mid=b+e>>1;
		int left=node<<1;
		int right=left|1;

		update(left,b,mid,p,v);
		update(right,mid+1,e,p,v);
		tree[node]=max(tree[left],tree[right]);
	}

	pii query(int node,int b,int e,int l,int r) {
		if(b > r || e < l) return {0,0};

		if(b >=l && e <=r ) return tree[node];

		int mid=b+e>>1;
		int left=node<<1;
		int right=left|1;

		return max(query(left,b,mid,l,r) , query(right,mid+1,e,l,r));

	}
} st;

int main() {
	int n,m,q;
	cin>>n>>m>>q;

	for(int i=1;i<=n;i++) {
		scanf("%d",&p[i]);
	}

	for(int i=1;i<=m;i++) {
		scanf("%d%d",&L[i], &R[i]);
	}

	for(int i=1;i<=q;i++) {
		scanf("%d %d", &tp[i], &id[i]);

		if(tp[i]==2) usd[id[i]] = true;
	}
	rt.init(n);

	for(int i=1;i<=m;i++) {
		if(!usd[i]) rt.unite(L[i],R[i],inf);
	}

	for(int i=q;i>0;i--) {
		if(tp[i] == 2) rt.unite(L[id[i]],R[id[i]],i);
	}

	for(int i=1;i<=n;i++) {
	    if(rt.findrep(i) == i) {
	        rt.dfs(i);
	    }
	}

	for(int i=1;i<=n;i++) {
		st.update(1,1,n,rt.in[i],p[i]);
	}
	bool dn[mxn]={};

	for(int i=1;i<=q;i++) {
		if(tp[i] == 1) {
			pii rg= rt.range(id[i],i);
			pii x = st.query(1,1,n,rg.f,rg.s);

			if(x.f == 0) {
				printf("0\n");
			} else {
				printf("%d\n", x.f);
				if(dn[x.s]) continue;
				st.update(1,1,n,x.s,0);
			}
		}
	}

}

/*
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀⠀⠀⢀⡀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⡖⠁⠀⠀⠀⠀⠀⠀⠈⢲⣄
⠀⠀⠀⠀⠀⠀⠀⠀⣼⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣧
⠀⠀⠀⠀⠀⠀⠀⣸⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣇
⠀⠀⠀⠀⠀⠀⠀⣿⣿⡇⠀⢀⣀⣤⣤⣤⣤⣀⡀⠀⢸⣿⣿
⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣔⢿⡿⠟⠛⠛⠻⢿⡿⣢⣿⣿⡟
⠀⠀⠀⠀⣀⣤⣶⣾⣿⣿⣿⣷⣤⣀⡀⢀⣀⣤⣾⣿⣿⣿⣷⣶⣤⡀
⠀⠀⢠⣾⣿⡿⠿⠿⠿⣿⣿⣿⣿⡿⠏⠻⢿⣿⣿⣿⣿⠿⠿⠿⢿⣿⣷⡀
⠀⢠⡿⠋⠁⠀⠀⢸⣿⡇⠉⠻⣿⠇⠀⠀⠸⣿⡿⠋⢰⣿⡇⠀⠀⠈⠙⢿⡄
⠀⡿⠁⠀⠀⠀⠀⠘⣿⣷⡀⠀⠰⣿⣶⣶⣿⡎⠀⢀⣾⣿⠇⠀⠀⠀⠀⠈⢿
⠀⡇⠀⠀⠀⠀⠀⠀⠹⣿⣷⣄⠀⣿⣿⣿⣿⠀⣠⣾⣿⠏⠀⠀⠀⠀⠀⠀⢸
⠀⠁⠀⠀⠀⠀⠀⠀⠀⠈⠻⢿⢇⣿⣿⣿⣿⡸⣿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠈
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣼⣿⣿⣿⣿⣧⡀
⠀⠀⠀⠐⢤⣀⣀⢀⣀⣠⣴⣿⣿⠿⠋⠙⠿⣿⣿⣦⣄⣀⠀⠀⣀⡠⠂
⠀⠀⠀⠀⠀⠈⠉⠛⠛⠛⠛⠉⠀⠀⠀⠀⠀⠈⠉⠛⠛⠛⠛⠋⠁
              vsriram1012
*/
#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
#define ii pair<int,int>
#define ll long long
// #define uint128 __uint128_t
// #define int128 __int128
#define pll pair<ll,ll>
// order_of_key(k), find_by_order(k)
#define ordered_set \
    tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
#define iiordered_set \
    tree<pll, null_type,less<pll>, rb_tree_tag,tree_order_statistics_node_update>
using namespace std;
auto clk=clock();
mt19937_64 rang(chrono::high_resolution_clock::now().time_since_epoch().count());
ll rng(ll lim) {
    uniform_int_distribution<ll> uid(0,lim-1);
    return uid(rang);
}
#define rd(x)   scanf("%d",&x);
#define numSetBits(x) __builtin_popcountll(x)
#define MOD 1000000007
// #define MOD 998244353
#define left(x) (x<<1)
#define right(x)    ((x<<1)|1)
// #define mid(l,r)    ((l+r)>>1)
const ll INFl=1e18;
#define vi vector<int>
#define vvi vector<vi>
#define vl vector<long long>
#define vvl vector<vl>
#define forl(i,n) for(int i=0;i<n;i++)
#define fore(i,n) for(int i=1;i<=n;i++)
#define debug(x)    cout<<"DEBUG: "<<x<<endl;
ll power(ll a,ll b, ll m=MOD)
{
    ll res=1;
    while(b>0)
    {
        if(b&1)
            res=(res*a)%m;
        a=(a*a)%m;
        b>>=1;
    }
    return res;
}
ll inverse(ll a,ll m=MOD)
{
    return power(a,m-2,m);
}
int ceil(int a,int b)
{
    return (a+b-1)/b;
}
#define sz(x) (x.size())
#define vll vector<pll>
#define vii vector<ii>
#define vvii vector<vii>
#define F first
#define S second
#define forl(i,n) for(int i=0;i<n;i++)
#define fore(i,n) for(int i=1;i<=n;i++)
#define CASE(t) cout<<"Case #"<<(t)<<": ";
#define INF 1020000000
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) ((a)*(b)/gcd(a,b))
#define all(x)  x.begin(),x.end()
#define mp make_pair
#define pb push_back
#define print(x)    \
    for(auto it=x.begin();it!=x.end();it++) cout<<*it<<' '; cout<<endl;
#define print2d(x)  \
    for(auto it1=x.begin();it1!=x.end();it1++) {print((*it1));}
#define printii(x)  \
        for(auto it=x.begin();it!=x.end();it++) cout<<it->F<<' '<<it->S<<endl;
vvl matmul(const vvl &a,const vvl &b,ll M=MOD)
{
    int n=a.size(),m=a[0].size(),l=b[0].size();
    assert(m==b.size());
    vvl c(n,vl(l,0));
    forl(i,n)forl(j,l)forl(k,m)
    {
        c[i][j]=(c[i][j]+a[i][k]*b[k][j])%M;
    }
    return c;
}
vvl matpow(vvl a,ll p,ll M=MOD)
{
    assert(a.size()==a[0].size());
    int n=a.size();
    vvl res(n,vl(n,0));
    forl(i,n)   res[i][i]=1;
    while(p>0)
    {
        if(p&1) res=matmul(res,a,M);
        a=matmul(a,a,M);
        p>>=1;
    }
    return res;
}
void sieve(vi& primes,int mx)
{
    vi is_comp(mx,0);
    for(int i=2;i<mx;i++)
    {
        if(!is_comp[i])
            primes.pb(i);
        for(int j=0;j<primes.size()&&primes[j]*i<mx;j++)
        {
            is_comp[i*primes[j]]=1;
            if(i%primes[j]==0)
                break;
        }
    }
}
int euc(int a,int b,int &x,int &y){
    if(!b){x=1;y=0;return a;}
    int x1,y1,g=euc(b,a%b,x1,y1);
    x=y1;y=x1-a/b*y1;
    return g;
}
int crt(int a,int n,int b,int m){
    int dif=b-a,x,y,g=euc(n,m,x,y),l=lcm(n,m);
    if(dif%g)   return -1;
    int res=(((x*dif/g)%(m/g))*n%l+a)%l;
    if(res<0)   res+=l;
    return res;
}
#define fastio ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL)
void solve();
void init();
signed main()
{
    // #ifndef loc
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // #endif
    fastio;
    init();
    signed T=1;
    // cin>>T;
    fore(t,T)
    {
        // CASE(t);
        solve();
    }

#ifdef loc
        cout<<"~~~~~~~~~~~~~~~~~~~~~~~~"<<endl<<"Time elapsed: "
        <<(double)(clock()-clk)/CLOCKS_PER_SEC<<endl;
#endif
}

void init()
{

}
vii split;
struct UnionFind
{
    int n;
    vi p;
    vvi x;
    UnionFind(int N)
    {
        n=N;
        p.assign(N,0);
        x.resize(N);
        for(int i=0;i<N;i++)
            p[i]=i,x[i].pb(i);
    }
    int FindSet(int i)
    {
        return (p[i]==i)?i:(p[i]=FindSet(p[i]));
    }
    bool isSameSet(int i,int j)
    {
        return FindSet(i)==FindSet(j);
    }
    void UnionSet(int i,int j,int idx)
    {
        int p1=FindSet(i);
        int p2=FindSet(j);
        if(p1!=p2)
        {
            if(sz(x[p1])>=sz(x[p2])){
                p[p2]=p1;
                for(int t:x[p2]){
                    x[p1].pb(t);
                }
                split[idx]=mp(p1,p2);
            }
            else{
                p[p1]=p2;
                for(int t:x[p1]){
                    x[p2].pb(t);
                }
                split[idx]=mp(p2,p1);
            }
        }
    }
    void disp()
    {
        for(int i=0;i<n;i++)
            cout<<p[i]<<' ';
        cout<<endl;
    }
};
void solve()
{
    int n,m,q;
    cin>>n>>m>>q;
    vi p(n);
    forl(i,n)   cin>>p[i];
    UnionFind uf(n);
    vii edges(m);
    split.assign(q+5,mp(-1,-1));
    vector<bool> avail(m,true);
    forl(i,m){
        int u,v;
        cin>>u>>v;u--;v--;
        edges[i]=mp(u,v);
    }
    // printii(edges);
    vii queries(q+5);
    forl(i,q){
        int t,x;
        cin>>t>>x;x--;
        queries[i]=mp(t,x);
        if(t==2)    avail[x]=false;
    }
    forl(i,m){
        if(avail[i]){
            uf.UnionSet(edges[i].F,edges[i].S,q);
        }
    }
    for(int i=q-1;i>=0;i--){
        int t,x;
        t=queries[i].F,x=queries[i].S;
        if(t==1) split[i].F=uf.FindSet(x);
        else uf.UnionSet(edges[x].F,edges[x].S,i);
    }
    vector<multiset<int>> val(n);
    forl(i,n){
        if(uf.p[i]==i){
            vi &tmp=uf.x[i];
            for(int x:tmp){
                val[i].insert(p[x]);
            }
        }
    }
    forl(i,q){
        int t,x;
        t=queries[i].F,x=queries[i].S;
        if(t==1){
            int id=split[i].F;
            if(val[id].empty()) cout<<0<<endl;
            else{
                int mx=*val[id].rbegin();
                cout<<mx<<endl;
                val[id].erase(val[id].find(mx));
            }
        }
        else{
            int p1=split[i].F,p2=split[i].S;
            if(p1==-1)  continue;
            vi &tmp=uf.x[p2];
            for(int v:tmp){
                if(val[p1].count(p[v])){
                    val[p1].erase(p[v]);
                    val[p2].insert(p[v]);
                }
            }
        }
    }
}

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Query{
	int opt,x,rx,ry;
}q[500005];
int n,m,Q,fa[200005],ex[300005],ey[300005],del[300005],sz[300005],bel[200005],a[200005],used[200005];
vector<int> h[200005];
int gf(int x){
	return fa[x]==x?x:gf(fa[x]);
}
inline int Query(int x)
{
	while(h[x].size()&&(bel[h[x].back()]!=x||used[h[x].back()])) h[x].pop_back();
	if(!h[x].size()) return 0;
	int ans=h[x].back();
	h[x].pop_back(),used[ans]=1;
	return ans;
}
int main() {
	scanf("%d%d%d",&n,&m,&Q);
	for(int i=1,x;i<=n;i++)scanf("%d",&x),h[fa[i]=i].push_back(a[i]=x),sz[i]=1;
	for(int i=1;i<=m;i++)scanf("%d%d",&ex[i],&ey[i]);
	for(int i=1;i<=Q;i++){
		scanf("%d%d",&q[i].opt,&q[i].x);
		if(q[i].opt==2)del[q[i].x]=1;
	}
	for ( int i=1;i<=m;i++ ) if(!del[i])
	{
		int fx=gf(ex[i]),fy=gf(ey[i]);
		if(fx==fy) continue;
		if(sz[fx]>sz[fy]) swap(fx,fy);
		for ( int j=0;j<h[fx].size();j++ ) h[fy].push_back(h[fx][j]);
		fa[fx]=fy,sz[fy]+=sz[fx];
	}
	for(int i=1;i<=m;i++){
		if(del[i])continue;
		int x=gf(ex[i]),y=gf(ey[i]);
		if(x==y)continue;
		if(sz[x]>sz[y])swap(x,y);
		for ( int j=0;j<h[x].size();j++ ) h[y].push_back(h[x][j]);
		fa[x]=y,sz[y]+=sz[x];
	}
	for(int i=Q;i>=1;i--){
		int x=ex[q[i].x],y=ey[q[i].x];
		if(q[i].opt==1||gf(x)==gf(y))continue;
		x=gf(x),y=gf(y);
		if(sz[x]>sz[y])swap(x,y);
		q[i].rx=x,fa[x]=y,sz[y]+=sz[x];
		for ( int j=0;j<h[x].size();j++ ) h[y].push_back(h[x][j]);
	}
	for(int i=1;i<=n;i++)sort(h[i].begin(),h[i].end()),bel[a[i]]=gf(i);
	for(int i=1,u;i<=Q;i++){
		if(q[i].opt==1)printf("%d\n",u=Query(gf(q[i].x)));
		else if(q[i].rx){
			for ( int j=0;j<h[q[i].rx].size();j++ ) bel[h[q[i].rx][j]]=q[i].rx;
			for(int j:h[q[i].rx])bel[j]=q[i].rx;
			fa[q[i].rx]=q[i].rx;
		}
	}
	return 0;
}

#include <bits/stdc++.h>
#define For(i,a,b) for ( int i=(a);i<=(b);i++ )
#define Dow(i,b,a) for ( int i=(b);i>=(a);i-- )
#define GO(i,x) for ( int i=head[x];i;i=e[i].nex )
#define mem(x,s) memset(x,s,sizeof(x))
#define cpy(x,s) memcpy(x,s,sizeof(x))
#define YES return puts("YES"),0
#define NO return puts("NO"),0
#define GG return puts("-1"),0
#define pb push_back
using namespace std;

struct IO
{
	#define MAXSIZE (1 << 20)
	#define isdigit(x) (x >= '0' && x <= '9')
  	char buf[MAXSIZE],*p1,*p2;
  	char pbuf[MAXSIZE],*pp;
  	IO():p1(buf),p2(buf),pp(pbuf){}
  	inline char gc() {
    	return getchar();
    	if (p1==p2) p2=(p1=buf)+fread(buf,1,MAXSIZE,stdin);
    	return p1==p2?' ':*p1++;
  	}
	inline bool blank(char ch) {return ch==' '||ch =='\n'||ch == '\r'||ch == '\t';}
  	template <class T>
  	inline void read(T &x)
	{
	    register double tmp=1;register bool sign=0; x=0;
	    register char ch=gc();
	    for (;!isdigit(ch);ch=gc()) if(ch=='-') sign=1;
	    for (;isdigit(ch);ch=gc()) x=x*10+(ch-'0');
	    if (ch=='.') for (ch=gc();isdigit(ch);ch=gc()) tmp/=10.0,x+=tmp*(ch-'0');
	    if (sign) x=-x;
  	}
  	inline void read(char *s)
	{
    	register char ch=gc();
		for (;blank(ch);ch=gc());
		for (;!blank(ch);ch=gc()) *s++=ch;
    	*s=0;
  	}
  	inline void read(char &c) {for(c=gc();blank(c);c=gc());}
  	template<class t> inline void write(t x){
		if(x<0) putchar('-'),write(-x);
		else{if(x>9) write(x/10);putchar('0'+x%10);}
	}
} io;

const int mod=1e9+7;
const int mo=998244353;
const int N=5e5+5;

int n,m,T,a[N],col[N],qx[N],qy[N],fa[N],siz[N];
int ux[N],uy[N],del[N],ok[N];
vector<int> g[N];

struct Node
{
	int op,x,qx;
};
Node q[N];

inline int find(int x) { return fa[x]==x?x:find(fa[x]); }

inline int Query(int x)
{
	while(g[x].size()&&(col[g[x].back()]!=x||ok[g[x].back()])) g[x].pop_back();
	if(!g[x].size()) return 0;
	int ans=g[x].back();
	g[x].pop_back(),ok[ans]=1;
	return ans;
}

signed main()
{
	io.read(n),io.read(m),io.read(T);
	For(i,1,n) io.read(a[i]),g[i].pb(a[i]),fa[i]=i,siz[i]=1;
	For(i,1,m) io.read(ux[i]),io.read(uy[i]);
	For(i,1,T)
	{
		int opt,x;
		io.read(opt),io.read(x);
		q[i]=(Node){opt,x,0};
		if(opt==2) del[x]=1;
	}
	For(i,1,m) if(!del[i])
	{
		int fx=find(ux[i]),fy=find(uy[i]);
		if(fx==fy) continue;
		if(siz[fx]>siz[fy]) swap(fx,fy);
		For(j,0,(int)g[fx].size()-1) g[fy].pb(g[fx][j]);
		fa[fx]=fy,siz[fy]+=siz[fx];
	}
	Dow(i,T,1)
	{
		int op=q[i].op,x=q[i].x;
		int fx=find(ux[x]),fy=find(uy[x]);
		if(fx==fy||op==1) continue;
		if(siz[fx]>siz[fy]) swap(fx,fy);
		fa[fx]=fy,siz[fy]+=siz[fx],q[i].qx=fx;
		For(j,0,(int)g[fx].size()-1) g[fy].pb(g[fx][j]);
	}
	For(i,1,n) sort(g[i].begin(),g[i].end()),col[a[i]]=find(i);
	For(i,1,T)
	{
		int op=q[i].op,x=q[i].x;
		if(op==1) io.write(Query(find(x))),puts("");
		else if(q[i].qx)
		{
			For(j,0,g[q[i].qx].size()-1) col[g[q[i].qx][j]]=q[i].qx;
			fa[q[i].qx]=q[i].qx;
		}
	}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<double> vd;
typedef vector<string> vs;
typedef vector<pii> vii;
typedef vector<pll> vll;
typedef vector<pdd> vdd;
typedef vector<vl> vvl;
typedef vector<vd> vvd;
const int mod = 1000000007;
const vi mods = {998244353,1000000007,1000000009};
const ll inf = 3e18;
const double pi = acos(-1.0);
const double eps = 0.0000001;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
#define rep(i,a,b) for(ll i=(a);i<(b);++i)
#define trav(a,x) for(auto&a:x)
#define all(x) begin(x),end(x)
#define sz(x) ((int)(x).size())
#define fll(xs,x,a) fill(&x,&x+sizeof(xs)/sizeof(x)-1,a)//fll(dp,dp[0][0],inf)
#define has(x,a) (x.find(a)!=end(x))
#define pc(x) __builtin_popcountll(x)
#define pb push_back
#define fi first
#define se second
template<class...K> using umap = unordered_map<K...>;
template<class...K> using uset = unordered_set<K...>;

const int N=500100;
int n,m,q,u,v,ty,x,p[N],par[N],siz[N];
umap<int,set<pii>>mns;
umap<int,vi>g;
int egs[N][3],qs[N][2];
uset<int>lt;

void build(){
  rep(i,0,n){
    mns[i].insert({p[i],i});
    par[i]=i;
    siz[i]=1;
  }
}

inline int fnd(int x){
  return par[x]==x?x:fnd(par[x]);
}

bool unn(int e){
  int x=egs[e][0],y=egs[e][1];
  int rx=fnd(x),ry=fnd(y);
  if(rx==ry)return 0;
  if(siz[rx]<siz[ry])swap(rx,ry);
  siz[rx]+=siz[ry];
  par[ry]=rx;
  g[rx].pb(ry);
  egs[e][2]=ry;
  trav(mny,mns[ry])mns[rx].insert(mny);
  mns[ry].clear();
  return 1;
}

void dfs(int x,int rm,int ad){
  if(p[x]){
    pll mn={p[x],x};
    mns[rm].erase(mns[rm].find(mn));
    mns[ad].insert(mn);
  }
  trav(nx,g[x])dfs(nx,rm,ad);
}

bool splt(int e){
  if(egs[e][2]==-1)return 0;
  int ry=egs[e][2];
  int rx=fnd(ry);
  g[par[ry]].pop_back();
  par[ry]=ry;
  dfs(ry,rx,ry);
  return 1;
}

int getmn(int x){
  int rx=fnd(x);
  if(!sz(mns[rx]))return 0;
  auto pp=--end(mns[rx]);
  p[pp->se]=0;
  int mn=pp->fi;
  mns[rx].erase(pp);
  return mn;
}

int main() {
  cin.sync_with_stdio(0);
  cin.tie(0);
  cout.precision(13);

  cin>>n>>m>>q;
  rep(i,0,n)cin>>p[i];
  build();
  rep(i,0,m){
    cin>>u>>v;
    u--;v--;
    egs[i][0]=u,egs[i][1]=v,egs[i][2]=-1;
  }
  rep(_q,0,q){
    cin>>ty>>x;
    x--;
    qs[_q][0]=ty,qs[_q][1]=x;
    if(ty==2)lt.insert(x);
  }
  rep(i,0,m){
    if(has(lt,i))continue;
    unn(i);
  }
  for(int _q=q-1;_q>=0;_q--){
    ty=qs[_q][0],x=qs[_q][1];
    if(ty!=2)continue;
    unn(x);
  }
  rep(_q,0,q){
    ty=qs[_q][0],x=qs[_q][1];
    if(ty==1)cout<<getmn(x)<<"\n";
    else splt(x);
  }

  return 0;
}

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using ull = unsigned long long;
using ld = long double;
#define all(a) (a).begin(),(a).end()

template<typename T1, typename T2> inline void chkmin(T1 & x, const T2 & y) {if (y < x) x = y;}
template<typename T1, typename T2> inline void chkmax(T1 & x, const T2 & y) {if (x < y) x = y;}

const int N = 1e6 + 10, M = 1e6, Q = 1e6;
int n, m, q;
int p[N];
pair<int, int> e[M];

int type[Q], query[Q];

void read() {
    cin >> n >> m >> q;
    for (int i = 0; i < n; ++i) {
        cin >> p[i];
    }
    for (int i = 0; i < m; ++i) {
        cin >> e[i].first >> e[i].second;
        e[i].first--;
        e[i].second--;
    }
    for (int i = 0; i < q; ++i) {
        cin >> type[i] >> query[i];
        query[i]--;
    }
}

int par[N + M];

int getPar(int v) {
    if (v == par[v]) return v;
    return par[v] = getPar(par[v]);
}

void uni(int a, int b) {
    assert(a != b);
    assert(a == getPar(a));
    //cout << a << " " << getPar(a) << endl;
    //cout << b << " " << getPar(b) << endl;
    assert(b == getPar(b));
    par[a] = b;
}

void init() {
    iota(par, par + n + m, 0);
}

vector<int> g[N + M];
int topG;

void add(int u, int v) {
    //cout << "add: u = " << u << " v = " << v << endl;
    u = getPar(u);
    v = getPar(v);
    if (u == v) return;
    int root = topG++;
    //cout << "root = " << root << endl;
    g[root].push_back(u);
    g[root].push_back(v);
    uni(u, root);
    uni(v, root);
}

bool used[M];

int tin[N], tout[N], timer = 0;

void dfs(int v) {
    used[v] = true;
    tin[v] = timer++;
    for (auto i : g[v]) {
        if (used[i]) continue;
        dfs(i);
    }
    tout[v] = timer - 1;
}

struct Node{
    int pos, val;
    Node() {
        pos = -1, val = -1;
    }
    Node(int _pos, int _val) {
        pos = _pos, val = _val;
    }
};

Node merge(const Node& a, const Node& b) {
    if (a.val < b.val) {
        return b;
    } else {
        return a;
    }
}

struct SegmentTree{
    int n;
    vector<Node> tree;
    vector<int> pos;
    SegmentTree() {}

    void build(int v, int tl, int tr, const vector<int>& a) {
        if (tl >= tr) return;
        if (tl == tr - 1) {
            //cout << "tl = " << tl << " a[tl] = " << a[tl] << endl;
            tree[v] = Node(tl, a[tl]);
            pos[tl] = v;
            return;
        }
        int tm = (tl + tr) / 2;
        build(v * 2, tl, tm, a);
        build(v * 2 + 1, tm, tr, a);
        tree[v] = merge(tree[v * 2], tree[v * 2 + 1]);
    }

    SegmentTree(const vector<int>& a) {
        n = a.size();
        tree.assign(4 * n, Node());
        pos.assign(n, 0);
        build(1, 0, n, a);
        /*
        for (int i = 0; i < n; ++i) {
            tree[i] = Node(i, a[i]);
        }*/
    }

    Node get(int v, int tl, int tr, int l, int r) {
        if (tl >= r || tr <= l) return Node();
        if (tl >= l && tr <= r)
            return tree[v];
        int tm = (tl + tr) / 2;
        return merge(get(v * 2, tl, tm, l, r), get(v * 2 + 1, tm, tr, l, r));
    }

    Node get(int l, int r) {
        assert(l >= 0 && r < n);
        return get(1, 0, n, l, r + 1);
        /*
        Node ans;
        for (int i = l; i <= r; ++i) {
            ans = merge(ans, tree[i]);
        }
        return ans;*/
    }
    void clear(int v) {
        assert(v != -1);
        assert(v >= 0 && v < n);
        tree[pos[v]] = Node(v, 0);
        v = pos[v] / 2;
        while (v) {
            tree[v] = merge(tree[v * 2], tree[v * 2 + 1]);
            v /= 2;
        }
    }
};

int myRoot[Q];
SegmentTree tree;

void build() {
    init();
    for (int i = 0; i < q; ++i) {
        if (type[i] == 2) {
            used[query[i]] = true;
        }
    }
    /*cout << "used = " << endl;
    for (int i = 0; i < m; ++i) {
        cout << used[i] << " ";
    }
    cout << endl;*/
    topG = n;
    for (int i = 0; i < m; ++i) {
        if (!used[i]) {
            add(e[i].first, e[i].second);
        }
    }
    for (int i = q - 1; i >= 0; --i) {
        if (type[i] == 1) {
            myRoot[i] = getPar(query[i]);
        } else if (type[i] == 2) {
            add(e[query[i]].first, e[query[i]].second);
        }
    }
    //cout << "topG = " << topG << endl;
    //assert(n + m == topG);
    fill(used, used + n + m, false);
    for (int i = topG - 1; i >= 0; --i) {
        if (!used[i]) {
            dfs(i);
        }
    }
    vector<int> a(n + m, -1);
    for (int i = 0; i < n; ++i) {
        a[tin[i]] = p[i];
    }
    tree = SegmentTree(a);
}

int topAns;
int ans[Q];

void solve() {
    topAns = 0;
    for (int i = 0; i < q; ++i) {
        if (type[i] == 1) {
            auto have = tree.get(tin[myRoot[i]], tout[myRoot[i]]);
            //cout << "have = ";
            //cout << have.pos << " " << have.val << endl;
            ans[topAns++] = have.val;
            tree.clear(have.pos);
        }
    }
}

void run() {
    build();
    solve();
}

void write() {
    for (int i = 0; i < topAns; ++i) {
        cout << ans[i] << "\n";
    }
}

signed main() {
    ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0), cout.precision(20), cout.setf(ios::fixed);
    read();
    run();
    write();
    return 0;
}

#include <algorithm>
#include <cstdio>
using namespace std;
int const maxn = 400003;
int n = 0, m = 0, q = 0, cPoint = 0;
int p[maxn];
struct Edge {
	int u, e;
	int id;
};
Edge E[maxn];
int deleteTime[maxn];
inline bool operator<(Edge const &lhs, Edge const &rhs) { return deleteTime[lhs.id] > deleteTime[rhs.id]; }

int opt[500003], Sec[500003];

int head[maxn], nxt[maxn], to[maxn], cnt = 0;
inline void insert(int u, int e) {
	nxt[++cnt] = head[u];
	head[u] = cnt;
	to[cnt] = e;
}

int fath[maxn];
inline int find(int x) { return fath[x] == x ? x : fath[x] = find(fath[x]); }
int ti[maxn];
void CreateTheTree() {
	std::sort(E + 1, E + m + 1);
	for (int i = 1; i <= 2 * n; ++i)
		fath[i] = i;
	cPoint = n;
	for (int i = 1; i <= m; ++i) {
		if (find(E[i].u) == find(E[i].e)) continue;
		++cPoint;
		ti[cPoint] = deleteTime[E[i].id];
		insert(cPoint, find(E[i].u));
		insert(cPoint, find(E[i].e));
		fath[find(E[i].u)] = cPoint;
		fath[find(E[i].e)] = cPoint;
	}
}

int fa[20][maxn], Ldfn[maxn], Rdfn[maxn];
int dfn[maxn], idfn[maxn];
void dfs(int x, int f) {
	fa[0][x] = f;
	for (int j = 1; j <= 18; ++j)
		fa[j][x] = fa[j - 1][fa[j - 1][x]];
	if (x <= n) {
		Ldfn[x] = Rdfn[x] = dfn[x] = ++dfn[0];
		idfn[dfn[x]] = x;
		return;
	}
	Ldfn[x] = cPoint + 1, Rdfn[x] = 0;
	for (int i = head[x]; i; i = nxt[i]) {
		dfs(to[i], x);
		Ldfn[x] = std::min(Ldfn[x], Ldfn[to[i]]);
		Rdfn[x] = std::max(Rdfn[x], Rdfn[to[i]]);
	}
}

struct MX {
	int v, pos;
};
MX operator|(MX const &lhs, MX const &rhs) { return lhs.v > rhs.v ? lhs : rhs; }
MX mx[maxn << 2];
void CreateSeg(int po, int L, int R) {
	if (L == R) {
		mx[po].v = p[idfn[L]];
		mx[po].pos = idfn[L];
		return;
	}
	int mid = (L + R) >> 1;
	CreateSeg(po << 1, L, mid);
	CreateSeg(po << 1 | 1, mid + 1, R);
	mx[po] = mx[po << 1] | mx[po << 1 | 1];
}
void Modify(int po, int L, int R, int x) {
	if (L == R) {
		mx[po].v = p[idfn[L]];
		return;
	}
	int mid = (L + R) >> 1;
	if (x <= mid)
		Modify(po << 1, L, mid, x);
	else
		Modify(po << 1 | 1, mid + 1, R, x);
	mx[po] = mx[po << 1] | mx[po << 1 | 1];
}
MX query(int po, int L, int R, int l, int r) {
	if (l <= L && R <= r)
		return mx[po];
	int mid = (L + R) >> 1;
	if (r <= mid)
		return query(po << 1, L, mid, l, r);
	else if (l > mid)
		return query(po << 1 | 1, mid + 1, R, l, r);
	else
		return query(po << 1, L, mid, l, r) | query(po << 1 | 1, mid + 1, R, l, r);
}

int jump(int x, int time) {
	for (int j = 18; ~j; --j)
		if (ti[fa[j][x]] > time)
			x = fa[j][x];
	return x;
}
int main() {
	scanf("%d %d %d", &n, &m, &q);
	for (int i = 1; i <= n; ++i)
		scanf("%d", p + i);
	for (int i = 1; i <= m; ++i) {
		scanf("%d %d", &E[i].u, &E[i].e);
		E[i].id = i;
		deleteTime[i] = q + 1;
	}
	for (int i = 1; i <= q; ++i) {
		scanf("%d %d", opt + i, Sec + i);
		if (opt[i] == 2) deleteTime[Sec[i]] = i;
	}
	CreateTheTree();
	for (int i = 1; i <= cPoint; ++i)
		if (fath[i] == i) dfs(i, 0);
	CreateSeg(1, 1, n);

	for (int i = 1; i <= q; ++i)
		if (opt[i] == 1) {
			int x = jump(Sec[i], i);
			MX res = query(1, 1, n, Ldfn[x], Rdfn[x]);
			printf("%d\n", res.v);
			p[res.pos] = 0;
			Modify(1, 1, n, dfn[res.pos]);
		}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;

/* useful defines with short names */
#define st first
#define nd second
#define pb push_back
#define pp pop_back
#define all(x) (x).begin(), (x).end()
#define lb(a, b, c) lower_bound(a, b, c)
#define ub(a, b, c) upper_bound(a, b, c)
#define forn(i, n) for (int i = 0; i < (n); ++i)
#define ford(i, n) for (int i = (n) - 1; i >= 0; --i)
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define trav(a, x) for (auto& a : x)
#define len(x) (int)(x).size()
#define low(x) ((x) & (-(x))) // lowest bit in number
#define ispow(x) low(x) == (x) // is power of two
#define subm(m, mask) for (int m = ((mask) - 1) & (mask); m; m = (m - 1) & (mask)) // iterate through submasks
#define pct(x) __builtin_popcount(x) // number of set bits in x
#define bits(x) (31 - __builtin_clz(x)) // floor(log2(x))

/* useful typedefs with short names */
typedef long long	ll;
typedef double 	db;
typedef long double ldb;
typedef complex<db> cd;
typedef string      str;

typedef pair<int, int>	pii;
typedef pair<ll, ll>	pll;
typedef pair<db, db>	pdb;
typedef pair<ldb, ldb>	pldb;
typedef pair<int, ll>	pil;
typedef pair<ll, int>	pli;

template<typename T = int>
using vv = vector<T>;

template<typename T1 = int, typename T2 = int>
using umap = unordered_map<T1, T2>;

template<typename T = int>
using uset = unordered_set<T>;

typedef vector<int>		vi;
typedef vector<ll>		vl;
typedef vector<str>      vs;
typedef vector<char>	vc;
typedef vector<bool>     vb;
typedef vector<db>		vdb;
typedef vector<ldb>		vldb;
typedef vector<pii>		vpii;
typedef vector<pll>		vpll;
typedef vector<pdb>		vpdb;
typedef vector<pldb>	vpldb;
typedef vector<pil>		vpil;
typedef vector<pli>		vpli;
typedef vector<vi> 		vvi;
typedef vector<vl>       vvl;

/* pair<T1, T2> operators: +, -, +=, -=, *, *=, -(unary) */
template<typename T1, typename T2>
pair<T1, T2> operator+(const pair<T1, T2>& a, const pair<T1, T2>& b);
template<typename T1, typename T2>
pair<T1, T2>& operator+=(pair<T1, T2>& a, const pair<T1, T2>& b);
template<typename T1, typename T2>
pair<T1, T2> operator-(const pair<T1, T2>& p);
template<typename T1, typename T2>
pair<T1, T2> operator-(const pair<T1, T2>& a, const pair<T1, T2>& b);
template<typename T1, typename T2>
pair<T1, T2>& operator-=(pair<T1, T2>& a, const pair<T1, T2>& b);
template<typename T1, typename T2, typename T3>
pair<T1, T2> operator*(const pair<T1, T2>& p, T3 mult);
template<typename T1, typename T2, typename T3>
pair<T1, T2> operator*(T3 mult, const pair<T1, T2>& p);

/* modular arithmetic class implementation */
template<int MOD=1'000'000'007>
struct modular
{
    int val;

    modular(ll v = 0) {
        if (v < 0) v = v % MOD + MOD;
        if (v >= MOD) v %= MOD;
        val = int(v);
    }
    modular(uint64_t v) {
        if (v >= MOD) v %= MOD;
        val = int(v);
    }

    modular(int v) : modular(ll(v)) {}
    modular(unsigned v) : modular(uint64_t(v)) {}

    static int inv_mod(int a, int m = MOD) {
        // https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Example
        int g = m, r = a, x = 0, y = 1;
        while (r != 0) {
            int q = g / r;
            g %= r; swap(g, r);
            x -= q * y; swap(x, y);
        }
        return x < 0 ? x + m : x;
    }

    explicit operator int() const { return val; }
    explicit operator unsigned() const { return val; }
    explicit operator ll() const { return val; }
    explicit operator uint64_t() const { return val; }
    explicit operator double() const { return val; }
    explicit operator long double() const { return val; }

    modular& operator+=(const modular &other) {
        val -= MOD - other.val;
        if (val < 0) val += MOD;
        return *this;
    }

    modular& operator-=(const modular &other) {
        val -= other.val;
        if (val < 0) val += MOD;
        return *this;
    }

    static unsigned fast_mod(uint64_t x, unsigned m = MOD) {
#if !defined(_WIN32) || defined(_WIN64)
        return unsigned(x % m);
#endif
        // Optimized mod for Codeforces 32-bit machines.
        // x must be less than 2^32 * m for this to work, so that x / m fits in an unsigned 32-bit int.
        unsigned x_high = unsigned(x >> 32), x_low = unsigned(x);
        unsigned quot, rem;
        asm("divl %4\n"
            : "=a" (quot), "=d" (rem)
            : "d" (x_high), "a" (x_low), "r" (m));
        return rem;
    }

    modular& operator*=(const modular &other) {
        val = fast_mod(uint64_t(val) * other.val);
        return *this;
    }

    modular& operator/=(const modular &other) {
        return *this *= other.inv();
    }

    friend modular operator+(const modular &a, const modular &b) { return modular(a) += b; }
    friend modular operator-(const modular &a, const modular &b) { return modular(a) -= b; }
    friend modular operator*(const modular &a, const modular &b) { return modular(a) *= b; }
    friend modular operator/(const modular &a, const modular &b) { return modular(a) /= b; }

    modular& operator++() {
        val = val == MOD - 1 ? 0 : val + 1;
        return *this;
    }

    modular& operator--() {
        val = val == 0 ? MOD - 1 : val - 1;
        return *this;
    }

    modular operator++(int) { modular before = *this; ++*this; return before; }
    modular operator--(int) { modular before = *this; --*this; return before; }

    modular operator-() const {
        return val == 0 ? 0 : MOD - val;
    }

    friend bool operator==(const modular &a, const modular &b) { return a.val == b.val; }
    friend bool operator!=(const modular &a, const modular &b) { return a.val != b.val; }
    friend bool operator<(const modular &a, const modular &b) { return a.val < b.val; }
    friend bool operator>(const modular &a, const modular &b) { return a.val > b.val; }
    friend bool operator<=(const modular &a, const modular &b) { return a.val <= b.val; }
    friend bool operator>=(const modular &a, const modular &b) { return a.val >= b.val; }

    modular inv() const {
        return inv_mod(val);
    }

    modular pow(int64_t p) const {
        if (p < 0)
            return inv().pow(-p);
        modular a = *this, result = 1;
        while (p > 0) {
            if (p & 1)
                result *= a;
            p >>= 1;
            if (p > 0)
                a *= a;
        }
        return result;
    }

    friend ostream& operator<<(ostream &os, const modular &m) {
        return os << m.val;
    }
};

/* scanf with template */
template<typename T> T scanf_t();

/* scanf template specializations */
template<>  int            scanf_t();
template<>  ll             scanf_t();
template<>  db             scanf_t();
template<>  ldb            scanf_t();
template<>  char           scanf_t();
template<>  float          scanf_t();
template<>  str 	       scanf_t();
str         scanf_t(int);

/* short names for scanf template specializations */
int     (*si)()     =  scanf_t<int>;
ll      (*sl)()     =  scanf_t<ll>;
db      (*sdb)()    =  scanf_t<db>;
ldb     (*sldb)()   =  scanf_t<ldb>;
char    (*sc)()     =  scanf_t<char>;
float   (*sf)()     =  scanf_t<float>;
str 	   (*ss)()     =  scanf_t<str>;

/* printf template functions */
template<typename T> void printf_t(const T&, char='\n', FILE* = stdout);
template<typename T> void printf_t(const T*, char='\n', FILE* = stdout);
template<typename T> void printf_t(T*, char='\n', FILE* = stdout);
template<typename T1, typename T2> void printf_t(const pair<T1, T2>&, char='\n', FILE* = stdout);
template<typename T, typename Alloc, template<typename, typename> class Container>
void printf_t(const Container<T, Alloc>&, char='\n', FILE* = stdout);

/* varadic print that uses printf */
void print();
template<typename T> void _print(char endl, const T&);
template<typename T, typename... Args> void _print(char endl, const T&, const Args&...);
template<typename T> void _print(char endl, T*, T*);
template<typename T> void _print(char endl, T*, int);
template<typename... Args> void print(const Args&...);

/* variadic print without newline at the end */
template<typename... Args> void prt(const Args&...);
template<typename T> void prt(T*, T*);
template<typename T> void prt(T*, int);

/* variadic print to stderr that uses printf */
template<typename T>
void __dbg(const char*, const T&);
template<typename T, typename... Args>
void __dbg(const char*, const T&, const Args&...);
template<typename... Args>
void _dbg(const char*, const Args&...);
template<typename T>
void _dbg(const char*, T*, T*, char='\n', char=' ');
template<typename T>
void _dbg(const char*, T*, int, char='\n', char=' ');

/* when debugging to stderr, grab also names of variables */
#ifdef LOCAL
	#define dbg(...) _dbg(#__VA_ARGS__, __VA_ARGS__)
#else
	#define dbg(...) 13
#endif

/* read to array from standard input with scanf */
template<typename T> void in(T*, int);
/* read to standard C++ container with scanf and push_back */
template<typename T, typename Alloc, template<typename, typename> class Container>
void sv(Container<T, Alloc>&, int);
template<typename T, typename Alloc>
void sv(vector<T, Alloc>&, int);

/* write an array to standard output */
template<typename It> void out(It, It, char='\n', char=' ', FILE* = stdout);
template<typename It> void out(It, int, char='\n', char=' ', FILE* = stdout);
/* write standard C++ container to standard output */
template<typename Container> void pv(const Container&, char='\n', char=' ', FILE* = stdout);

/* debug functions */
template<typename T>
void print_bits(T x, int=0);

/* useful variables, functions, definitions*/
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
#define shuffle(a, b) shuffle(a, b, rng)
template<typename T> T rand(T a, T b);
template<typename T> T rand(T n);
template<typename It> It uniq(It begin, It end);
template<typename T> void uniq(vv<T>& v);

/* short names for printf template specializations */
void pi(const int&, char='\n');
void pl(const ll&, char='\n');
void pd(const db&, char='\n');
void pld(const ldb&, char='\n');
void pf(const float&, char='\n');
void pc(const char&, char='\n');
void ps(const str&, char='\n');

/* geometry */
template<typename T1, typename T2>
ll cross(const pair<T1, T2>& p1, const pair<T1, T2>& p2);
template<typename T1, typename T2>
ll dot(const pair<T1, T2>& p1, const pair<T1, T2>& p2);
template<typename T1, typename T2>
ldb vlen(const pair<T1, T2>& v);

/* useful, general purpose algorithms */
ll russian(ll, ll, ll);
ll fastpow(ll, ll, ll);
ll slowpow(ll, ll, ll);
ll extgcd(ll, ll, ll&, ll&);
ll _gcd(ll, ll);
ll _lcm(ll, ll);
ll _inv(ll, ll);

/* useful constants */
const  int  INF   =  1e9;
const  ll   LINF  =  1e18;
const  ll   M     =  1e9 + 7;
// const  ll   M 	   =  998244353LL;
const  ldb  PI    =  acos(-1);
const  ldb  PI_2  =  PI / 2;

typedef modular<M> mod;

struct query {
	int id;
	int type;
	int v;
};

struct seg_tree {
	int p = 1;
	vpii t;
	const pii N = {-INF, -INF};
	seg_tree(int n) {
		while (p < n)
			p <<= 1;
		t.resize(2 * p, N);
	}
	void set_pos(int pos, int val) {
		t[pos + p] = {val, pos};
	}
	void build() {
		for (int i = p - 1; i > 0; --i)
			t[i] = max(t[i + i], t[i + i + 1]);
	}
	pii get_max(int l, int r) {
		l += p; r += p;
		pii res = N;
		while (l < r) {
			if (l & 1)
				res = max(res, t[l++]);
			if (r & 1)
				res = max(res, t[--r]);
			l >>= 1;
			r >>= 1;
		}
		return res;
	}
	void remove(int v) {
		v += p;
		t[v].st = 0;
		v >>= 1;
		while (v) {
			t[v] = max(t[v + v], t[v + v + 1]);
			v >>= 1;
		}
	}
};

template<>
void printf_t(const query& q, char endl, FILE* out) {
	dbg(q.id, q.type, q.v);
	// fprintf(out, "(%d %d %d)%c", q.id, q.type, q.v, endl);
}

const int N = 3e5 + 7;
int p[N], par[N], pos[N];
pii edge[N];
vi verts[N];
bool del[N];

int Find(int a) {
	return a == par[a] ? a : par[a] = Find(par[a]);
}

int Union(int a, int b) {
	if ((a = Find(a)) == (b = Find(b)))
		return -1;
	if (len(verts[a]) > len(verts[b]))
		swap(a, b);
	assert(!verts[a].empty());
	verts[b].insert(verts[b].end(), all(verts[a]));
	par[a] = b;
	return verts[a][0];
}

int main()
{
	int n = si(), m = si(), q = si();
	in(p + 1, n);
	forn (i, m) {
		int u = si(), v = si();
		edge[i] = {u, v};
	}

	vv<query> que;
	forn (i, q) {
		int type = si(), v = si() - 1;
		if (type == 2)
			del[v] = true;
		que.pb({q - i, type, v});
	}
	forn (i, m)
		if (!del[i])
			que.pb({0, 2, i});

	reverse(all(que));

	rep (i, 1, n) {
		par[i] = i;
		verts[i].pb(i);
	}

	vi after(len(que));
	forn (i, len(que)) {
		auto& qq = que[i];
		if (qq.type == 2)
			after[i] = Union(edge[qq.v].st, edge[qq.v].nd);
	}

	dbg(que);
	dbg(after);

	vb done(n + 1);
	set<int> borders = {0};
	seg_tree s(n);
	int cnt = 0;

	rep (i, 1, n) {
		int f = Find(i);
		if (!done[f]) {
			done[f] = true;
			dbg(f, i, verts[f]);
			trav (v, verts[f]) {
				s.set_pos(cnt, p[v]);
				dbg(cnt, p[v]);
				pos[v] = cnt++;
			}
			borders.insert(cnt);
		}
	}

	s.build();

	dbg(borders);
	dbg(pos + 1, n);

	for (int i = len(que) - 1; i >= 0; --i) {
		auto& qq = que[i];
		if (qq.type == 1) {
			int pp = pos[qq.v + 1];
			auto g = borders.upper_bound(pp);
			auto l = next(g, -1);
			pii maxi = s.get_max(*l, *g);
			print(maxi.st);
			dbg(maxi, *l, *g);
			s.remove(maxi.nd);
		}
		else {
			borders.insert(pos[after[i]]);
		}
	}

	return 0;
}

/* scanf template specilizations */
template<> int scanf_t() { int x; scanf("%d", &x); return x; }
template<> db scanf_t() { db x; scanf("%lf", &x); return x; }
template<> ll scanf_t() { ll x; scanf("%lld", &x); return x; }
template<> ldb scanf_t() { ldb x; scanf("%Lf", &x); return x; }
template<> char scanf_t() { char x; scanf(" %c", &x); return x; }
template<> float scanf_t() { float x; scanf("%f", &x); return x; }

/* printf template specilizations */
template<> void printf_t(const int& x, char end, FILE* out) { fprintf(out, "%d%c", x, end); }
template<> void printf_t(const ll& x, char end, FILE* out) { fprintf(out, "%lld%c", x, end); }
template<> void printf_t(const db& x, char end, FILE* out) { fprintf(out, "%.8lf%c", x, end); }
template<> void printf_t(const ldb& x, char end, FILE* out) { fprintf(out, "%.10Lf%c", x, end); }
template<> void printf_t(const float& x, char end, FILE* out) { fprintf(out, "%f%c", x, end); }
template<> void printf_t(const char& x, char end, FILE* out) { fprintf(out, "%c%c", x, end); }
template<> void printf_t(const str& x, char end, FILE* out) { fprintf(out, "%s%c", x.c_str(), end); }
template<> void printf_t(const char* x, char end, FILE* out) { fprintf(out, "%s%c", x, end); }
template<> void printf_t(char* x, char end, FILE* out) { fprintf(out, "%s%c", x, end); }
template<> void printf_t(const mod& x, char end, FILE* out) { printf_t(x.val, end, out); }
template<> void printf_t(const uint64_t& x, char end, FILE* out) { fprintf(out, "%lu%c", x, end); }
template<> void printf_t(const uint32_t& x, char end, FILE* out) { fprintf(out, "%u%c", x, end); }
template<> void printf_t(const bool& x, char end, FILE* out) { fprintf(out, "%d%c", x, end); }
template<> void printf_t(const long& x, char end, FILE* out) { fprintf(out, "%ld%c", x, end); }
template<typename T1, typename T2> void printf_t(const pair<T1, T2>& x, char end, FILE* out) { printf_t(x.st, ' ', out); printf_t(x.nd, end, out); }
template<typename T, typename Alloc, template<typename, typename> class Container>
void printf_t(const Container<T, Alloc>& v, char end, FILE* out) { pv(v, end, ' ', out); }

/* scanf str of unknown length */
template<>
str scanf_t()
{
	int size = 8;
	char* s = (char*)malloc(size * sizeof(char));
	char c;
	while (isspace(c = getchar()));
	*s = c;
	int i = 1;
	while (!isspace(c = getchar()))
	{
		s[i++] = c;
		if (i == size)
			s = (char*)realloc(s, size *= 2);
	}
	s[i] = '\0';
	str res(s);
	free(s);
	return res;
}

/* make print() possible */
void print() { printf("\n"); }

/* variadic print base case */
template<typename T> void _print(char endl, const T& last) { printf_t(last, endl); }

/* variadic print */
template<typename T, typename... Args>
void _print(char endl, const T& first, const Args&... rest)
{
	printf_t(first, ' ');
	_print(endl, rest...);
}

/* print array from begin iterator to end iterator */
template<typename T>
void _print(char endl, T* begin, T* end) { out(begin, end, endl); }

/* print n elements from of array starting from begin iterator */
template<typename T>
void _print(char endl, T* begin, int n) { out(begin, begin + n, endl); }

/* variadic print with newline at the end */
template<typename... Args>
void print(const Args&... args) { _print('\n', args...); }

/* variadic print with no newline at the end */
template<typename... Args>
void prt(const Args&... args) { _print(' ', args...); }

/* analogous to print(T*, T*) */
template<typename T>
void prt(T* begin, T* end) { _print(' ', begin, end); }

/* analogous to print(T*, int) */
template<typename T>
void prt(T* begin, int n) { _print(' ', begin, n); }

/* variadic __dbg base case */
template<typename T>
void __dbg(const char* s, const T& x)
{
	fprintf(stderr, "%s = ", s);
	printf_t(x, ' ', stderr);
}

/* variadic __dbg */
template<typename T, typename... Args>
void __dbg(const char* s, const T& x, const Args&... rest)
{
	int bracket = 0;
	char c;
	while ((c = *s) != ',' || bracket)
	{
		fprintf(stderr, "%c", *s++);
		switch (c)
		{
			case '(':
			case '{':
			case '[':
				++bracket;
				break;
			case ')':
			case '}':
			case ']':
				--bracket;
		}
	}
	fprintf(stderr, " = ");
	printf_t(x, '\0', stderr);
	fprintf(stderr, ",");
	__dbg(s + 1, rest...);
}

/* variadic _dbg - print braces around */
template<typename... Args>
void _dbg(const char* s, const Args&... rest)
{
	fprintf(stderr, "[ ");
	__dbg(s, rest...);
	fprintf(stderr, "]\n");
}

/* _dbg array from begin to end */
template<typename T>
void _dbg(const char* s, T* begin, T* end, char endl, char sep)
{
	fprintf(stderr, "[ ");
	while (*s != ',')
		fprintf(stderr, "%c", *s++);
	fprintf(stderr, " = ");
	out(begin, end, ' ', sep, stderr);
	fprintf(stderr, "]%c", endl);
}

/* _dbg n elements of array starting from begin */
template<typename T>
void _dbg(const char* s, T* begin, int n, char endl, char sep)
{
	_dbg(s, begin, begin + n, endl, sep);
}

/* scanf n variables of type T */
template<typename T>
void in(T* begin, int n)
{
	while (n--)
		*begin++ = scanf_t<T>();
}

/* scanf n variables of type T to standard C++ container and push them back */
template<typename T, typename Alloc, template<typename, typename> class Container>
void sv(Container<T, Alloc>& v, int n)
{
	auto it = std::back_inserter(v);
	while (n--)
		*it = scanf_t<T>();
}

/* little optimization */
template<typename T, typename Alloc>
void sv(vector<T, Alloc>& v, int n)
{
	v.reserve(n);
	auto it = std::back_inserter(v);
	while (n--)
		*it = scanf_t<T>();
}

/* printf array to standard output */
template<typename It>
void out(It begin, It end, char endl, char sep, FILE* outs)
{
	if (begin == end)
	{
		fprintf(outs, "%c", endl);
		return;
	}
	while (next(begin) != end)
		printf_t(*begin++, sep, outs);
	printf_t(*begin, endl, outs);
}

/* printf array to standard output */
template<typename It>
void out(It begin, int n, char endl, char sep, FILE* outs) { out(begin, begin + n, endl, sep, outs); }

/* printf standard C++ container to standard output */
template<typename Container>
void pv(const Container& v, char end, char sep, FILE* outs) { out(all(v), end, sep, outs); }

/* implementation short named functions for template specializations */
void  pi(const   int&     x, char end)  {  printf_t(x, end);  }
void  pl(const   ll&      x, char end)  {  printf_t(x, end);  }
void  pd(const   db&      x, char end)  {  printf_t(x, end);  }
void  pld(const  ldb&     x, char end)  {  printf_t(x, end);  }
void  pf(const   float&   x, char end)  {  printf_t(x, end);  }
void  pc(const   char&    x, char end)  {  printf_t(x, end);  }
void  ps(const   str&  x, char end)     {  printf_t(x, end);  }

/* pair<T1, T2> operators: +, -, +=, -=, *, *=, -(unary) */
template<typename T1, typename T2>
pair<T1, T2> operator+(const pair<T1, T2>& a, const pair<T1, T2>& b) { return { a.st + b.st, a.nd + b.nd }; }
template<typename T1, typename T2>
pair<T1, T2>& operator+=(pair<T1, T2>& a, const pair<T1, T2>& b) { a.st += b.st; a.nd += b.nd; return a; }
template<typename T1, typename T2>
pair<T1, T2> operator-(const pair<T1, T2>& p) { return { -p.st, -p.nd }; }
template<typename T1, typename T2>
pair<T1, T2> operator-(const pair<T1, T2>& a, const pair<T1, T2>& b) { return { a.st - b.st, a.nd - b.nd }; }
template<typename T1, typename T2>
pair<T1, T2>& operator-=(pair<T1, T2>& a, const pair<T1, T2>& b) { a.st -= b.st; a.nd -= b.nd; return a; }
template<typename T1, typename T2, typename T3>
pair<T1, T2> operator*(const pair<T1, T2>& p, T3 mult) { return {p.st * mult, p.nd * mult}; }
template<typename T1, typename T2, typename T3>
pair<T1, T2> operator*(T3 mult, const pair<T1, T2>& p) { return {p.st * mult, p.nd * mult}; }

/* geometry functions */
template<typename T1, typename T2>
ll cross(const pair<T1, T2>& p1, const pair<T1, T2>& p2) { return p1.st * p2.nd - p1.nd * p2.st; }
template<typename T1, typename T2>
ll dot(const pair<T1, T2>& p1, const pair<T1, T2>& p2) { return p1.st * p2.st + p1.nd * p2.nd; }
template<typename T1, typename T2>
ldb vlen(const pair<T1, T2>& v) { return sqrtl(dot(v, v)); }

/* russian peasants algorithm */
ll russian(ll a, ll k, ll m)
{
	ll res = 0LL;
	while (k)
	{
		if (k & 1LL)
			res = (res + a) % m;
		a = (a + a) % m;
		k >>= 1;
	}
	return res;
}

/* fast power - a^k % m */
ll fastpow(ll a, ll k, ll m)
{
	ll res = 1LL;
	while (k)
	{
		if (k & 1LL)
			res = (res * a) % m;
		a = (a * a) % m;
		k >>= 1;
	}
	return res;
}

/* fast power with russian peasants algorithm */
ll slowpow(ll a, ll k, ll m)
{
	ll res = 1LL;
	while (k)
	{
		if (k & 1LL)
			res = russian(res, a, m);
		a = russian(a, a, m);
		k >>= 1;
	}
	return res;
}

/* greatest common divisor of a and b */
ll _gcd(ll a, ll b)
{
	while (b)
		swap(a %= b, b);
	return a;
}

/* least common multiple of a and b */
ll _lcm(ll a, ll b)
{
	return a / _gcd(a, b) * b;
}

/* calculate inverse of a modulo */
ll _inv(ll a, ll p)
{
	return fastpow(a, p - 2, p);
}

/* extended Eucilean algorithm implementation - calculate a * k + b * l = GCD(a, b) */
ll extgcd(ll a, ll b, ll& k, ll& l)
{
	if (b == 0)
	{
		k = 1; l = 0;
		return a;
	}
	ll res = extgcd(b, a % b, l, k);
	l -= a / b * k;
	return res;
}

/* print bits of number x */
template<typename T>
void print_bits(T x, int force_len)
{
	assert(0 <= force_len && force_len <= 64);
	static char s[64];
	int i = 63;
	if (force_len)
		while (force_len--)
			s[i--] = '0' + (x & 1),
			x >>= 1;
	else
		while (x)
			s[i--] = '0' + (x & 1),
			x >>= 1;
	printf("%s\n", s + i + 1);
}

/* random number between a and b (integer or float depending on type T) */
template<typename T>
T rand(T a, T b)
{
	using dist = conditional_t<
		is_integral<T>::value,
		uniform_int_distribution<T>,
		uniform_real_distribution<T>
	>;
	return dist(a, b)(rng);
}

/* random number between 0 and n-1 */
template<typename T>
T rand(T n)
{
	static_assert(is_integral<T>::value, "Only integral type supported!");
	return uniform_int_distribution<T>(0, n - 1)(rng);
}

/* "delete" repeated occurences */
template<typename It>
It uniq(It begin, It end)
{
	sort(begin, end);
	return unique(begin, end);
}

/* delete non-unique elements from vector */
template<typename T>
void uniq(vv<T>& v) { v.erase(uniq(all(v)), v.end()); }

#include<bits/stdc++.h>
#define rep(i,x,y) for(int i=x,I=y+1;i<I;++i)
#define per(i,x,y) for(int i=x,I=y-1;i>I;--i)
using namespace std;
using ll=long long;
void cmax(int&x,const int&y){x=x>y?x:y;}
void cmin(int&x,const int&y){x=x<y?x:y;}
template<class T>istream&operator>>(istream&in,vector<T>&V){for(auto&x:V)in>>x;return in;}
template<class T>ostream&operator<<(ostream&out,const vector<T>&V){for(auto x:V)out<<x<<' ';return out;}
template<class T>void sort(vector<T>&V){sort(V.begin(),V.end());}
template<class T>void reverse(vector<T>&V){reverse(V.begin(),V.end());}
template<class T>int SZ(const vector<T>&V){return (int)V.size();}
void debug(){cerr<<"whxorz"<<'\n';}

const int N = 2e5 + 5;
const int M = 3e5 + 5;
const int Q = 5e5 + 5;
int n, m, q;
int _p[N];
int opt[Q], opx[Q];
struct Edge {
	int u, v, w;
	bool operator <(const Edge &rhs) const { return w > rhs.w; }
} edge[M];

const int T = N << 1;
vector <int> g[T];
int fa[T], val[T];
const int K = 19;
int f[T][K];

int find(const int &x) {
	if (x == fa[x])
		return x;
	else
		return fa[x] = find(fa[x]);
}

int sz[T], dfn[T], idx = 0;
void dfs(int u) {
	sz[u] = 1; dfn[u] = ++idx;
	for (auto v : g[u])
		if (!dfn[v]) { f[v][0] = u; dfs(v), sz[u] += sz[v]; }
}

pair <int, int> s[T << 2];
void up(int p) { s[p] = max(s[p << 1], s[p << 1 | 1]); }

void modify(int l, int r, int p, int x, int v) {
	if (l == r) { s[p] = make_pair(_p[v], v); return; }
	int mid = l + r >> 1;
	if (x <= mid) { modify(l, mid, p << 1, x, v); }
	else { modify(mid + 1, r, p << 1 | 1, x, v); }
	up(p);
}

pair <int, int> query(int ql, int qr, int l, int r, int p) {
	if (ql <= l && r <= qr) { return s[p]; }
	int mid = l + r >> 1;
	if (qr <= mid) { return query(ql, qr, l, mid, p << 1); }
	else if (ql > mid) { return query(ql, qr, mid + 1, r, p << 1 | 1); }
	else { return max(query(ql, qr, l, mid, p << 1), query(ql, qr, mid + 1, r, p << 1 | 1)); }
}

int main(){
	ios::sync_with_stdio(false); cin.tie(NULL);
	cin >> n >> m >> q;
	for (int i = 1; i <= n; i++) { cin >> _p[i]; }
	for (int i = 1; i <= m; i++) { int u, v; cin >> u >> v; edge[i].u = u; edge[i].v = v; edge[i].w = q + 1; }
	for (int i = 1; i <= q; i++) { cin >> opt[i] >> opx[i]; }
	for (int i = 1; i <= q; i++) { if (opt[i] == 2) { edge[opx[i]].w = i; } }
	sort(edge + 1, edge + m + 1);
	int tot = n;
	for (int i = 1; i <= n * 2; i++) { fa[i] = i; }
	for (int i = 1; i <= m; i++) {
		int x = find(edge[i].u), y = find(edge[i].v);
		if (x == y) { continue; }
		++tot; fa[x] = tot; fa[y] = tot; g[tot].push_back(x); g[tot].push_back(y); val[tot] = edge[i].w;
	}
	for (int i = tot; i >= 1; --i) if (!dfn[i]) { dfs(i); }
	for (int j = 1; j < K; j++) {
		for (int i = 1; i <= tot; i++) { f[i][j] = f[f[i][j - 1]][j - 1]; }
	}
	for (int i = 1; i <= n; i++) { modify(1, tot, 1, dfn[i], i); }
	for (int i = 1; i <= q; i++) {
		if (opt[i] == 2) { continue; }
		int x = opx[i];
		for (int j = K - 1; j >= 0; --j) {
			if (val[f[x][j]] > i) { x = f[x][j]; }
		}
		auto res = query(dfn[x], dfn[x] + sz[x] - 1, 1, tot, 1);
		int v = res.second; cout << _p[v] << '\n'; _p[v] = 0; modify(1, tot, 1, dfn[v], v);
	}
	return 0;
}

// code by a weak man named YJJ
#include <bits/stdc++.h>
#define filesolution freopen("data.in", "r", stdin), freopen("solution.out", "w", stdout)
#define filebrute freopen("data.in", "r", stdin), freopen("brute.out", "w", stdout)
#define filemakedata freopen("data.in", "w", stdout);
#define file(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
using namespace std;

template <typename T> void read(T &x) {
  x = 0; int f = 1;
  char ch = getchar();
  while (!isdigit(ch)) {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (isdigit(ch)) {
    x = x * 10 + (ch ^ 48);
    ch = getchar();
  }
  return x *= f, void();
}
template <typename T> void ckmax(T &a, T b) { a = b > a ? b : a; }
template <typename T> void ckmin(T &a, T b) { a = b < a ? b : a; }

///////////////////////////////////////////////////

#define ls p << 1
#define rs p << 1 | 1
#define mid ((l + r) >> 1)

const int N = 5e5 + 5;

int n, m, q, tot, U[N], V[N], del[N], fa[N], p[N], op[N], x[N], dfn[N], cnt, siz[N];
vector<int> g[N];
pair<int, int> w[N << 2];

inline void pushup(int p) {
  w[p] = max(w[ls], w[rs]);
}

void modify(int p, int l, int r, int x, int val) {
//  printf("modify(%d, %d, %d, %d, %d)\n", p, l, r, x, val);
  if (l == r) return w[p] = make_pair(val, l), void();
  if (x <= mid) modify(ls, l, mid, x, val);
  else modify(rs, mid + 1, r, x, val);
  pushup(p);
}

pair<int, int> query(int p, int l, int r, int x, int y) {
//  printf("query(%d, %d, %d, %d, %d)\n", p, l, r, x, y);
  if (y == 0) return make_pair(0, 0);
  if (x <= l && r <= y) return w[p];
  pair<int, int> res(0, 0);
  if (x <= mid) res = max(res, query(ls, l, mid, x, y));
  if (y > mid) res = max(res, query(rs, mid + 1, r, x, y));
  return res;
}

int find(int u) {
  if (fa[u] == u) return u;
  return fa[u] = find(fa[u]);
}

inline void merge(int u, int v) {
//  printf("merge(%d, %d)\n", u, v);
  u = find(u), v = find(v);
  if (u == v) return ;
  fa[u] = fa[v] = ++tot;
  fa[tot] = tot;
  g[tot].push_back(u);
  g[tot].push_back(v);
}

void dfs(int u) {
//  printf("dfs(%d)\n", u);
  dfn[u] = ++cnt, siz[u] = 1;
  if (u <= n) modify(1, 1, tot, dfn[u], p[u]);
  for (auto v : g[u]) {
    if (dfn[v]) continue;
    dfs(v), siz[u] += siz[v];
  }
}

int main() {
  read(n), read(m), read(q), tot = n;
  for (int i = 1; i <= n; i++) read(p[i]);
  for (int i = 1; i <= m; i++) read(U[i]), read(V[i]);
  for (int i = 1; i <= q; i++) {
    read(op[i]), read(x[i]);
    if (op[i] == 2) del[x[i]] = 1;
  }
  for (int i = 1; i <= n; i++) fa[i] = i;
  for (int i = 1; i <= m; i++) {
    if (!del[i]) merge(U[i], V[i]);
  }
  for (int i = q; i >= 1; i--) {
    if (op[i] == 2) {
      merge(U[x[i]], V[x[i]]);
    } else {
      x[i] = find(x[i]);
    }
  }
  ++tot;
  for (int i = 1; i < tot; i++) {
    if (fa[i] == i) {
      g[tot].push_back(i);
    }
  }
  dfs(tot);
  for (int i = 1; i <= q; i++) {
    if (op[i] == 1) {
      pair<int, int> ans;
      ans = query(1, 1, tot, dfn[x[i]], dfn[x[i]] + siz[x[i]] - 1);
      printf("%d\n", ans.first);
      modify(1, 1, tot, ans.second, 0);
    }
  }
  return 0;
}

#include <bits/stdc++.h>
#define DIMN 800010
using namespace std;
pair <int , int> x[DIMN] , w[DIMN];
int val[DIMN] , tt[DIMN] , f[DIMN] , pp[DIMN] , up[DIMN];
int aint[4 * DIMN] , poz , nn , elem , sol[DIMN];
vector <int> v[DIMN] , qry[DIMN];
int root (int x){
    if (tt[x] < 0)
        return x;
    return (tt[x] = root(tt[x]));
}

void update (int nod , int st , int dr , int poz , int nr){
    int mid = (st + dr) / 2;

    if (st == dr){
        aint[nod] = nr;
        return;
    }

    if (poz <= mid)
        update (2 * nod , st , mid , poz , nr);
    else update (2 * nod + 1 , mid + 1 , dr , poz , nr);

    if (val[aint[2 * nod]] > val[aint[2 * nod + 1]])
        aint[nod] = aint[2 * nod];
    else aint[nod] = aint[2 * nod + 1];

}

int query (int nod , int st , int dr , int l , int r){
    int mid = (st + dr) / 2 , idk = nn + 1 , aux;

    if (l <= st && dr <= r){
        return aint[nod];
    }

    if (l <= mid){
        aux = query (2 * nod , st , mid , l , r);
        if (val[aux] > val[idk])
            idk = aux;
    }

    if (mid + 1 <= r){
        aux = query (2 * nod + 1 , mid + 1 , dr , l , r);
        if (val[aux] > val[idk])
            idk = aux;
    }

    return idk;

}

void dfs (int nod , int tt){
    int i , vecin , nr;

    poz++;
    pp[nod] = poz;

    update (1 , 1 , nn , pp[nod] , nod);

    for (i = 0 ; i < v[nod].size() ; i++){
        vecin = v[nod][i];
        if (vecin != tt)
            dfs (vecin , nod);
    }

    up[nod] = poz;

}

void dfs2 (int nod , int tt){
    int i , vecin , nr;

    for (i = qry[nod].size() - 1 ; i >= 0 ; i--){

        nr = query(1 , 1 , nn , pp[nod] , up[nod]);

        //printf ("%d %d %d\n",nod , elem - qry[nod][i] + 1 , val[nr]);

        sol[elem - qry[nod][i] + 1] = val[nr];

        val[nr] = 0;

        update (1 , 1 , nn , pp[nr] , nr);

    }

    for (i = 0 ; i < v[nod].size() ; i++){
        vecin = v[nod][i];
        if (vecin != tt)
            dfs2 (vecin , nod);
    }

}

int main()
{
    FILE *fin = stdin;
    FILE *fout = stdout;
    int n , m , q , i , rx , ry;
    fscanf (fin,"%d%d%d",&n,&m,&q);
    for (i = 1 ; i <= n ; i++){
        fscanf (fin,"%d",&val[i]);
        tt[i] = -1;
    }

    for (i = 1 ; i <= m ; i++)
        fscanf (fin,"%d%d",&w[i].first,&w[i].second);

    for (i = 1 ; i <= q ; i++){
        fscanf (fin,"%d%d",&x[i].first,&x[i].second);
        if (x[i].first == 2)
            f[x[i].second] = 1;
    }

    for (i = 1 ; i <= m ; i++){

        if (!f[i]){

            rx = root(w[i].first);
            ry = root(w[i].second);

            if (rx != ry){
                if (tt[rx] < tt[ry]){
                    v[rx].push_back(ry);
                    tt[rx] += tt[ry];
                    tt[ry] = rx;
                }
                else {
                    v[ry].push_back(rx);
                    tt[ry] += tt[rx];
                    tt[rx] = ry;
                }
            }

        }

    }

    nn = n;

    for (i = q ; i ; i--){
        if (x[i].first == 2){ /// asta inseamna ca adaugi o muchie practic

            rx = root(w[x[i].second].first);
            ry = root(w[x[i].second].second);

            if (rx != ry){
                nn++;
                v[nn].push_back(rx);
                v[nn].push_back(ry);

                tt[nn] = tt[rx] + tt[ry];
                tt[rx] = nn;
                tt[ry] = nn;
            }

        }
        else {
            elem++;
            qry[root(x[i].second)].push_back(elem);
        }
    }

    for (i = 1 ; i <= nn ; i++){

        if (tt[i] < 0){
            dfs (i , 0);
        }

    }

    for (i = 1 ; i <= nn ; i++){

        if (tt[i] < 0){
            dfs2 (i , 0);
        }

    }

    for (i = 1 ; i <= elem ; i++){
        fprintf (fout,"%d\n",sol[i]);
    }

    return 0;
}

#include <bits/stdc++.h>
using namespace std;
const int QQ = 500000;
int P[200000];

// par[x] = y; x, prv
vector<pair<int, int>> undo_par[QQ+1];
// st[y].insert(v); y, v
vector<pair<int, int>> undo_st[QQ+1];

struct UnionFind {
    vector<int> par;
    vector<int> sz;
    vector<set<int>> st;

    UnionFind(int n=0){ if(n>0) initialize(n); }
    void initialize(int n){
        par.resize(n);
        sz.assign(n, 1);
        st.resize(n);
        for(int i=0; i<n; i++){
            par[i] = i;
            st[i].insert(P[i]);
        }
    }

    int find(int x){
        if(par[x] == x){
            return x;
        }else{
            return find(par[x]);
        }
    }

    bool unite(int x, int y, int t){
        x = find(x), y = find(y);
        if(x == y) return false;
        if(sz[x] > sz[y]) swap(x, y);
        undo_par[t].emplace_back(x, par[x]);
        par[x] = y;
        sz[y] += sz[x];
        for(int v : st[x]){
            st[y].insert(v);
            undo_st[t].emplace_back(y, v);
        }
        return true;
    }

    void undo(int t){
        for(auto [y, v] : undo_st[t]) st[y].erase(v);
        for(auto [x, prv] : undo_par[t]) par[x] = prv;
    }

    bool same(int x, int y){ return find(x) == find(y); }
    int size(int x){ return sz[find(x)]; }
};

int main(){
    int N, M, Q;
    cin >> N >> M >> Q;
    for(int i=0; i<N; i++) scanf("%d", &P[i]);
    vector<pair<int, int>> es(M);
    for(int i=0; i<M; i++){
        int a, b;
        scanf("%d %d", &a, &b);
        a--; b--;
        es[i] = {a, b};
    }
    vector<bool> e_live(M, true);
    vector<int> tp(Q), tv(Q);
    for(int q=0; q<Q; q++){
        scanf("%d %d", &tp[q], &tv[q]);
        tv[q]--;
        if(tp[q] == 2) e_live[tv[q]] = false;
    }

    UnionFind uf(N);
    for(int i=0; i<M; i++) if(e_live[i]) uf.unite(es[i].first, es[i].second, Q);
    for(int q=Q-1; q>=0; q--){
        if(tp[q] == 2){
            auto [a, b] = es[tv[q]];
            uf.unite(a, b, q);
        }
    }

    vector<bool> used(N+1);

    for(int q=0; q<Q; q++){
        if(tp[q] == 1){
            int c = uf.find(tv[q]), ans = 0;
            auto& st = uf.st[c];
            while(st.size() && used[*prev(st.end())]) st.erase(prev(st.end()));
            if(st.size()){
                auto it = prev(uf.st[c].end());
                ans = *it;
                used[ans] = true;
                uf.st[c].erase(it);
            }
            printf("%d\n", ans);
        }else{
            uf.undo(q);
        }
    }
    return 0;
}

#include <bits/stdc++.h>

using namespace std;

#ifdef NeverBeRed
#include "debug.h"
#else
#define debug(...) 9715
#endif
typedef long long ll;
typedef long double ld;
typedef complex<ld> point;
#define F first
#define S second

template<class node>
struct link_cut_tree
{
	bool connected(node* u, node* v) { return lca(u, v) != NULL; }

	int depth(node* u) { access(u); return get_sz(u->ch[0]); }

	node* get_root(node* u) // get root of LCT component
	{
		access(u);
		while (u->ch[0]) u = u->ch[0], u->push();
		return access(u), u;
	}

	node* ancestor(node* u, int k) // get k-th parent on path to root
	{
		k = depth(u) - k;
		assert(k >= 0);
		for (; ; u->push())
		{
			int sz = get_sz(u->ch[0]);
			if (sz == k) return access(u), u;
			if (sz < k) k -= sz+1, u = u->ch[1];
			else u = u->ch[0];
		}
		assert(0);
	}

	node* lca(node* u, node* v)
	{
		if (u == v) return u;
		access(u); access(v);
		if (!u->p) return NULL;
		u->splay(); return u->p ?: u;
	}

	void link(node* u, node* v) // make u parent of v
	{
		assert(!connected(u, v));
		make_root(v);
		access(u); set_link(v, u, 0); v->update();
	}

	void cut(node* u) // cut u from its parent
	{
		access(u);
		u->ch[0]->p = NULL;
		u->ch[0] = NULL;
		u->update();
	}

	void cut(node* u, node* v) // if u, v adj in tree
	{
		cut(depth(u) > depth(v) ? u : v);
	}

	void make_root(node* u) // make u root of LCT component
	{
		access(u);
		u->reverse();
		access(u);
		assert(!u->ch[0] && !u->ch[1]);
	}

	void access(node *u) // puts u on the preferred path, splay (right subtree is empty)
	{
		for (node* v = u, *pre = NULL; v; v = v->p)
		{
			v->splay(); // now update virtual children
			if (pre) v->update_vsub(pre, false);
			if (v->ch[1]) v->update_vsub(v->ch[1], true);
			v->ch[1] = pre; v->update(); pre = v;
		}
		u->splay(); assert(!u->ch[1]);
	}

	node* operator[](int i) { return &data[i]; }
	int operator[](node* i) { return i - &data[0]; }

	vector<node> data;
	link_cut_tree(int n) : data(n) {}
};

template<typename pnode>
struct splay_tree
{
	pnode ch[2], p;

	splay_tree() { ch[0] = ch[1] = p = NULL; }

	int dir()
	{
		if (!p) return -2; // root of LCT component
		if (p->ch[0] == this) return 0; // left child
		if (p->ch[1] == this) return 1; // right child
		return -1; // root of current splay tree
	}

	bool is_root() { return dir() < 0; }

	friend void set_link(pnode u, pnode v, int d)
	{
		if (v) v->p = u;
		if (d >= 0) u->ch[d] = v;
	}

	void rotate() // assume p and p->p propagated
	{
		assert(!is_root());
		int x = dir(); pnode g = p;
		set_link(g->p, static_cast<pnode>(this), g->dir());
		set_link(g, ch[x^1], x);
		set_link(static_cast<pnode>(this), g, x^1);
		g->update(); //update();
	}

	void splay() // bring this to top of splay tree
	{
		const pnode &self = static_cast<pnode>(this);
		while (!is_root() && !p->is_root())
		{
			p->p->push(), p->push(), self->push();
			dir() == p->dir() ? p->rotate() : self->rotate();
			self->rotate();
		}
		if (!is_root()) p->push(), self->push(), self->rotate();
		self->push(); self->update();
	}
};

template<typename pnode, class splay_tree_vchs>
struct splay_tree_lct : splay_tree<pnode>
{
	splay_tree_vchs vnode;

	using splay_tree<pnode>::ch;
	bool rev;
	int sz;

	splay_tree_vchs *root;

	splay_tree_lct() : splay_tree<pnode>() { root = NULL; rev = 0; sz = 1; }

	friend int get_sz(pnode u) { return u ? u->sz : 0; }

	void update()
	{
		sz = 1 + get_sz(ch[0]) + get_sz(ch[1]);
	}

	void push()
	{
	    if (rev)
	    {
	    	if (ch[0]) ch[0]->reverse();
	    	if (ch[1]) ch[1]->reverse();
	    	rev = 0;
	    }
	}

	void rotate()
	{
	    swap(vnode, this->p->vnode);
	    splay_tree<pnode>::rotate();
	}

	void splay()
	{
		auto v = &vnode;
	    bool r = !v->key;
	    splay_tree<pnode>::splay();
	    if (r && v->key)
	    {
	    	if (this->p->root->key == NULL) this->p->root = v;
	    	if (v->p) v->p->ch[v->p->ch[1] == &v->key->vnode] = v;
	    	if (v->ch[0]) v->ch[0]->p = v;
	    	if (v->ch[1]) v->ch[1]->p = v;
	    	v->key = static_cast<pnode>(this);
	    }
	}

	void reverse()
	{
		rev ^= 1;
		swap(ch[0], ch[1]);
	}

	void update_vsub(pnode v, bool add)
	{
		auto &u = root;
		if (add)
		{
			v->vnode = splay_tree_vchs(v);
			if (!u) { u = &v->vnode; return; }
			u->push();
			while (u->ch[1]) u = u->ch[1], u->push();
			u->ch[1] = &v->vnode;
			u->ch[1]->p = u;
			u = u->ch[1];
			u->splay();
		}
		else
		{
			auto x = &v->vnode;
			x->splay();
			if (!x->ch[0]) { u = x->ch[1]; }
			else if (!x->ch[1]) { u = x->ch[0]; }
			else
			{
				u = x->ch[0];
				u->p = NULL;
				u->push();
				while (u->ch[1]) u = u->ch[1], u->push();
				u->ch[1] = x->ch[1];
				x->ch[1]->p = u;
				u->splay();
			}
			if (u) u->p = NULL;
			x->key = NULL;
		}
	}
};

template<typename pnode>
struct splay_tree_vchs : splay_tree<splay_tree_vchs<pnode>*>
{
	using splay_tree<splay_tree_vchs<pnode>*>::ch;
	pnode key;

	int sub;

	splay_tree_vchs() : key(NULL) {};
	splay_tree_vchs(const pnode &key) : splay_tree<splay_tree_vchs<pnode>*>(), key(key) { build(); }

	void build()
	{
		sub = key->sub;
	}

	void update()
	{
		build();
		if (ch[0]) sub = max(sub, ch[0]->sub);
		if (ch[1]) sub = max(sub, ch[1]->sub);
	}

	void push() {}
};

struct node : splay_tree_lct<node*, splay_tree_vchs<node*>>
{
	int x, sub;

	node() : splay_tree_lct() { x = sub = 0; }

	void update()
	{
		splay_tree_lct::update();
		sub = x;
		if (root) sub = max(x, root->sub);
		if (ch[0]) sub = max(sub, ch[0]->sub);
		if (ch[1]) sub = max(sub, ch[1]->sub);
	}

	void push()
	{
		splay_tree_lct::push();
	}

	void reverse()
	{
		splay_tree_lct::reverse();
	}
};

int main()
{
	#ifdef TurnRed
		//freopen("a.in", "r", stdin);
		//freopen("a.out", "w", stdout);
	#endif

	ios_base::sync_with_stdio(0), cin.tie(0);

	int n, m, q;
	cin >> n >> m >> q;
	vector<int> p(n), who(n+1);
	link_cut_tree<node> lct(n);
	for (auto &i : p)
	{
		int u = &i-&p[0];
		cin >> i;
		who[i] = u;
		lct[u]->x = lct[u]->sub = i;
	}

	vector<pair<int, int>> edges(m);
	for (auto &i : edges)
		cin >> i.F >> i.S, --i.F, --i.S;

	vector<pair<int, int>> prio(m);
	for (int i = 0; i < m; ++i) prio[i] = { q+1, i };

	vector<pair<int, int>> queries(q);
	for (auto &i : queries)
	{
		cin >> i.F >> i.S, --i.S;
		if (i.F == 2) prio[i.S].F = &i-&queries[0];
	}

	vector<bool> alive(m);
	sort(prio.rbegin(), prio.rend());
	for (auto i : prio)
	{
		int u, v;
		tie(u, v) = edges[i.S];
		if (!lct.connected(lct[u], lct[v]))
		{
			alive[i.S] = true;
			lct.link(lct[u], lct[v]);
		}
	}

	for (auto que : queries)
	{
		if (que.F == 1)
		{
			auto u = lct[que.S];
			lct.access(u);
			cout << u->sub << "\n";
			if (u->sub != 0)
			{
				auto v = lct[who[u->sub]];
				lct.access(v);
				v->x = 0;
				v->update();
			}
		}
		else if (alive[que.S])
		{
			int u, v;
			tie(u, v) = edges[que.S];
			lct.cut(lct[u], lct[v]);
		}
	}

	return 0;
}

#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
#include<tuple>
#include<cassert>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define Per(i,sta,n) for(int i=n-1;i>=sta;i--)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
const ld eps = 1e-8;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
template<class T>bool chmax(T &a, const T &b) {if(a<b){a=b;return 1;}return 0;}
template<class T>bool chmin(T &a, const T &b) {if(b<a){a=b;return 1;}return 0;}

template <class S, S (*op)(S, S), S (*e)()> struct SegmentTree {
  public:
    SegmentTree() : SegmentTree(0) {}
    SegmentTree(int n) : SegmentTree(std::vector<S>(n, e())) {}
    SegmentTree(const std::vector<S>& v) : _n(int(v.size())) {
        log = ceil_pow2(_n);
        size = 1 << log;
        d = std::vector<S>(2 * size, e());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set_val(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < _n);
        return d[p + size];
    }

    S query(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        S sml = e(), smr = e();
        l += size;
        r += size;

        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }

    S all_query() { return d[1]; }

    template <bool (*f)(S)> int max_right(int l) {//f(op([l,r)))==trueを満たす最大のr
        return max_right(l, [](S x) { return f(x); });
    }
    template <class F> int max_right(int l, F f) {
        assert(0 <= l && l <= _n);
        assert(f(e()));
        if (l == _n) return _n;
        l += size;
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < size) {
                    l = (2 * l);
                    if (f(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*f)(S)> int min_left(int r) {//f(op([l,r)))==trueを満たす最小のl
        return min_left(r, [](S x) { return f(x); });
    }
    template <class F> int min_left(int r, F f) {
        assert(0 <= r && r <= _n);
        assert(f(e()));
        if (r == 0) return 0;
        r += size;
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < size) {
                    r = (2 * r + 1);
                    if (f(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

  private:
    int _n, size, log;
    std::vector<S> d;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }

    int ceil_pow2(int n) {
        int x = 0;
        while ((1U << x) < (unsigned int)(n)) x++;
        return x;
    }
};

struct UnionFind {
private:
    vector<int> par,ran;
    vector<int> edge,size;
    int n;
public:
    UnionFind(int x){
      n=x;
      par.resize(n,0);
      ran.resize(n,0);
      edge.resize(n,0);
      size.resize(n,1);
      rep(i,n){
        par[i]=i;
      }
    }
    int find(int x) {
        if (par[x]==x)return x;
        else return par[x]=find(par[x]);
    }
    void unite(int x, int y) {
        x=find(x),y=find(y);
        if (x==y){
            edge[x]++;
            return;
        }
        if (ran[x]<ran[y]) {
            par[x]=y;
            size[y]+=size[x];
            edge[y]+=edge[x]+1;
        }
        else {
            par[y]=x;
            size[x]+=size[y];
            edge[x]+=edge[y]+1;
            if (ran[x]==ran[y])ran[x]++;
        }
    }
    bool same(int x,int y) {
        return find(x)==find(y);
    }
    int getSize(int x){
        return size[find(x)];
    }
    int getEdge(int x){
        return edge[find(x)];
    }
};

struct T{
  int idx,h;
  T(int h,int idx):h(h),idx(idx){}
  T(){}
};

T F(T a,T b){
  if(a.h>=b.h) return a;
  return b;
}

T e1(){return T(0,0);}

int n,m,q;
int a[200010];
P e[300010],qs[500010];
vector<int> G[600010];
vector<int> S[500010];
vector<bool> is_root;
P sec[600010];
int p[300010],inv[300010];

void dfs(int s,int &id){
  sec[s].first=id+1;
  if(G[s].empty()) {
    id++;
    p[id]=s;
    inv[s]=id;
  }
  for(int t:G[s]){
    dfs(t,id);
  }
  sec[s].second=id+1;
}

void solve(){
  scanf("%d%d%d",&n,&m,&q);
  rep(i,n) scanf("%d",&a[i]);
  rep(i,m){
    scanf("%d%d",&e[i].first,&e[i].second);
    e[i].first--;e[i].second--;
  }
  vector<P> units={};
  vector<bool> used(m,false);
  rep(i,q){
    scanf("%d%d",&qs[i].first,&qs[i].second);
    qs[i].second--;
    if(qs[i].first==2) {
      units.push_back(P(i,qs[i].second));
      used[qs[i].second]=true;
    }
  }
  rep(i,m){
    if(!used[i]) units.push_back(P(q,i));
  }
  int U=n;
  UnionFind uf(n);is_root.resize(n,true);
  vector<int> nodes(n);rep(i,n) nodes[i]=i;
  per(i,units.size()){
    P u=units[i];
    int v1=uf.find(e[u.second].first),v2=uf.find(e[u.second].second);
    //cout << i << " " << e[u.second].first << " " << e[u.second].second << endl;
    if(uf.same(v1,v2)) continue;
    G[U].push_back(nodes[v1]);
    G[U].push_back(nodes[v2]);
    is_root[nodes[v1]]=false;
    is_root[nodes[v2]]=false;
    is_root.push_back(true);
    uf.unite(v1,v2);
    nodes[uf.find(v1)]=U;
    S[u.first].push_back(U);
    U++;
  }
  int id=-1;
  set<P> se;
  rep(i,U){
    if(!is_root[i]) continue;
    dfs(i,id);
    se.insert(P(sec[i].first,sec[i].second));
  }
  vector<T> vec(n);
  rep(i,n) vec[i]=T(a[p[i]],i);
  SegmentTree<T,F,e1> seg(vec);
  //rep(i,U) cout << sec[i].first << " " << sec[i].second << endl;
  rep(i,q){
    for(int z:S[i]){
      int t1=G[z][0],t2=G[z][1];
      se.erase(sec[z]);
      se.insert(sec[t1]);
      se.insert(sec[t2]);
    }
    if(qs[i].first==1){
      //cout << inv[qs[i].second] << endl;
      auto it=se.lower_bound(P(inv[qs[i].second],mod));it--;
      P p=(*it);
      //cout << p.first << " " << p.second << endl;
      T t=seg.query(p.first,p.second);
      printf("%d\n",t.h);
      seg.set_val(t.idx,T(0,t.idx));
    }
  }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout << fixed << setprecision(50);
    solve();
}

#include <bits/stdc++.h>
using namespace std;

int parent[200005], sizex[200005];
int deletedEdge[300005], smallParent[500005];
pair<int, int> edge[300005];

set<int, greater<int> > S[200005];
vector<int> P[200005], X[500005];
vector< pair<int, int> > query;

int find_parent(int x)
{
    if (x == parent[x])
        return x;

    return parent[x] = find_parent(parent[x]);
}

void unite(int a, int b, int indx)
{
    a = find_parent(a);
    b = find_parent(b);

    if (a == b)
        return;

    if (sizex[a] > sizex[b])
        swap(a, b);

    parent[a] = b;
    sizex[b] += sizex[a];

    for (auto p : P[a])
    {
        P[b].push_back(p);

        if (indx != -1)
            X[indx].push_back(p);
    }

    if (indx != -1)
        smallParent[indx] = a;

    P[a].clear();
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(NULL), cout.tie(NULL);

    int n, m, q;
    cin >> n >> m >> q;

    for (int i=1; i<=n; i++)
    {
        int p;
        cin >> p;
        P[i].push_back(p);
        parent[i] = i, sizex[i] = 1;
    }

    for (int i=1; i<=m; i++)
        cin >> edge[i].first >> edge[i].second;

    for (int i=0; i<q; i++)
    {
        int type, x;
        cin >> type >> x;

        query.push_back({type, x});

        if (type == 2)
            deletedEdge[x] = 1;
    }

    for (int i=1; i<=m; i++)
        if (!deletedEdge[i])
            unite(edge[i].first, edge[i].second, -1);

    for (int i=q-1; i>=0; i--)
    {
        if (query[i].first == 1)
            continue;

        int indx = query[i].second;
        int x = edge[indx].first, y = edge[indx].second;

        unite(x, y, i);
    }

    for (int i=1; i<=n; i++)
    {
        parent[i] = find_parent(i);

        for (auto p : P[i])
            S[i].insert(p);
    }

    for (int i=0; i<q; i++)
    {
        if (query[i].first == 1)
        {
            int root = parent[ query[i].second ];

            if (root == 0 || S[root].empty())
                cout << 0 << "\n";
            else
            {
                cout << *S[root].begin() << "\n";
                S[root].erase(S[root].begin());
            }
            continue;
        }

        if (X[i].empty())
            continue;

        int originalParent = parent[ X[i].back() ];
        int newParent = smallParent[i];

        for (auto x : X[i])
        {
            if (S[ originalParent ].find(x) == S[ originalParent ].end())
            {
                parent[x] = 0;
                continue;
            }

            parent[x] = newParent;
            S[ newParent ].insert(x);
            S[ originalParent ].erase(x);
        }
    }

    return 0;
}

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=500005;
const int maxm=500005;
const int maxq=500005;
const int inf=0x3f3f3f3f;
int n,m,Q,a[maxn],fa[maxn],x_[maxm],y_[maxm],u_[maxq],v_[maxq]; bool vis[maxm];
set<int> s[maxn];
set<int>::iterator it,itl,itr;
struct oper { int op,u; } q[maxq];
inline int find(int x) { return (x==fa[x])?x:fa[x]=find(fa[x]); }
/*
struct union_set
{
	int col[maxn],fa[maxn],cnt[maxn],x_[maxn],y_[maxn],tot;
	inline void init()
	{
		tot=0;
		for(int i=1;i<=n;i++) fa[i]=i,cnt[i]=1;
	}
	inline int find(int x) { while(x!=fa[x]) x=fa[x]; return x; }
	inline bool merge(int x,int y)
	{
		int u=find(x),v=find(y);
		tot++,x_[tot]=y_[tot]=-1;
		if(u==v) return false;
		if(cnt[u]>cnt[v]) swap(u,v);
		x_[tot]=u,y_[tot]=v;
		fa[u]=v,cnt[v]+=cnt[u];
		return true;
	}
	inline void cancel()
	{
		if(x_[tot]==-1) { tot--; return; }
		fa[x_[tot]]=x_[tot];
		cnt[y_[tot]]-=x_[tot];
		tot--;
	}
	inline void cover(int x,int y) { col[find(x)]=y; }
}s;
void solve(int l,int r,int ql,int qr)
{
	if(l>r || ql>qr) continue;

}
*/
int main()
{
	scanf("%d%d%d",&n,&m,&Q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=m;i++) scanf("%d%d",&x_[i],&y_[i]);
	for(int i=1;i<=Q;i++)
	{
		scanf("%d%d",&q[i].op,&q[i].u);
		if(q[i].op==2) vis[q[i].u]=1;
	}
	/*
	s.init();
	for(int i=1;i<=m;i++)
		if(!vis[i]) s.merge(x_[i],y_[i]);
	for(int i=1;i<=n;i++) id[i]=i;
	solve(1,Q,1,n);
	*/
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=m;i++)
		if(!vis[i])
		{
			int u=find(x_[i]),v=find(y_[i]);
			if(u!=v) fa[u]=v;
		}
	for(int i=1;i<=n;i++) s[find(i)].insert(a[i]);
	for(int i=Q;i;i--)
		if(q[i].op==2)
		{
			int u=find(x_[q[i].u]),v=find(y_[q[i].u]);
			if(u==v) continue;
			if(s[u].size()>s[v].size()) swap(u,v);
			u_[i]=u,v_[i]=v,fa[u]=v;
			for(it=s[u].begin();it!=s[u].end();it++)
				s[v].insert(*it);
		}
	static int sta[maxn],top;
	for(int i=1;i<=Q;i++)
		if(q[i].op==1)
		{
			int u=find(q[i].u);
			if(s[u].empty()) { puts("0"); continue; }
			printf("%d\n",*s[u].rbegin());
			s[u].erase(*s[u].rbegin());
		}
		else if(q[i].op==2)
		{
			if(!u_[i]) continue;
			int u=u_[i],v=v_[i]; fa[u]=u,top=0;
			for(it=s[u].begin();it!=s[u].end();it++)
			{
				itr=s[v].find(*it);
				if(itr==s[v].end()) sta[++top]=*it;
				else s[v].erase(itr);
			}
			for(;top;top--) s[u].erase(s[u].find(sta[top]));
		}
	return 0;
}

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <memory.h>

using namespace std;

int val[200005];
pair<int, int> e[300005];
bool del[300005];
int qT[500005], qV[500005];

int color[200005];

inline int repr(int x) {
  return color[x] == x ? x : (color[x] = repr(color[x]));
}

vector<int> f[200005];
pair<pair<int, int>, int> op[500005];

inline void join(int x, int y, int ind) {
  x = repr(x); y = repr(y);

  if (x != y) {
    if (f[x].size() < f[y].size())  swap(x, y);
    f[x].insert(f[x].end(), f[y].begin(), f[y].end());
    color[y] = x;

    if (ind != -1) {
      op[ind] = {{x, y}, y};
    }
  }
}

int root[200005];
set<pair<int, int>> ff[200005];

int main() {
  ios::sync_with_stdio(false);
  int n, m, q;
  cin >> n >> m >> q;
  for (int i = 0; i < n; ++i) cin >> val[i];
  for (int i = 0; i < m; ++i) {
    cin >> e[i].first >> e[i].second;
    e[i].first--; e[i].second--;
  }
  for (int i = 0; i < q; ++i) {
    cin >> qT[i] >> qV[i], qV[i]--;
    if (qT[i] == 2) del[qV[i]] = true;
  }

  for (int i = 0; i < n; ++i) {
    color[i] = i;
    f[i].push_back(i);
  }

  for (int i = 0; i < m; ++i) {
    if (del[i]) continue;
    join(e[i].first, e[i].second, -1);
  }

  for (int i = q - 1; i >= 0; --i) {
    if (qT[i] == 2) {
      join(e[qV[i]].first, e[qV[i]].second, i);
    }
  }

  for (int i = 0; i < n; ++i) {
    ff[repr(i)].insert({-val[i], i});
    root[i] = repr(i);
    // cout << i << "  " << repr(i) << endl;
  }

  for (int i = 0; i < q; ++i) {
    if (qT[i] == 1) {
      if (ff[root[qV[i]]].size() > 0) {
        set<pair<int, int>>::iterator it = ff[root[qV[i]]].begin();
        cout << -it->first << endl;
        val[it->second] = 0;
        ff[root[qV[i]]].erase(it);
      } else {
        cout << 0 << endl;
      }
    } else {
      for (int t : f[op[i].second]) {
        root[t] = op[i].first.second;
        if (val[t] > 0) {
          ff[op[i].first.first].erase({-val[t], t});
          ff[op[i].first.second].insert({-val[t], t});
        }
      }
    }
  }

  return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int, int>
#define ull unsigned ll
#define f first
#define s second
#define ALL(x) x.begin(),x.end()
#define SZ(x) (int)x.size()
#define SQ(x) (x)*(x)
#define MN(a,b) a = min(a,(__typeof__(a))(b))
#define MX(a,b) a = max(a,(__typeof__(a))(b))
#define pb push_back
#define SORT_UNIQUE(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#ifdef BALBIT
#define IOS()
#define bug(...) fprintf(stderr,"#%d (%s) = ",__LINE__,#__VA_ARGS__),_do(__VA_ARGS__);
template<typename T> void _do(T &&x){cerr<<x<<endl;}
template<typename T, typename ...S> void _do(T &&x, S &&...y){cerr<<x<<", ";_do(y...);}
#else
#define IOS() ios_base::sync_with_stdio(0);cin.tie(0);
#define endl '\n'
#define bug(...)
#endif

const int iinf = 1e9+10;
const ll inf = 1ll<<60;
const ll mod = 1e9+7 ;

void GG(){cout<<"0\n"; exit(0);}

ll mpow(ll a, ll n, ll mo = mod){ // a^n % mod
    ll re=1;
    while (n>0){
        if (n&1) re = re*a %mo;
        a = a*a %mo;
        n>>=1;
    }
    return re;
}

ll inv (ll b, ll mo = mod){
    if (b==1) return b;
    return (mo-mo/b) * inv(mo%b,mo) % mo;
}

const int maxn = 2e5+5;
const int maxm = 3e5+5;
vector<pii> g[maxn]; // to, index
//int par[maxn];
int dt[maxm]; // when this edge dies
int val[maxn];
bool dead[maxn];

//int find(int a) {
//    return a==par[a]?a:par[a] = find(par[a]);
//}

int n,m,q;
vector<int> pq[maxn];

const int BS = 300;

int col[maxn];
void dcol(int v, int c, int TT) {
    col[v] = c;
    if (!dead[val[v]])
        pq[c].pb(val[v]);
    for (pii &u : g[v]) {
        if (dt[u.s] > TT && col[u.f] == 0) {
            dcol(u.f,c,TT);
        }
    }
}

int A[maxn], B[maxn];
vector<pii> G[maxn];

int bg = 0, frm = -1;
bool seen[maxn];
vector<int> touch;
void dfs(int v, int TT) {
    seen[v] = 1;
//    touch.pb(v);
    if (SZ(pq[v]) && pq[v].back() > bg) {
        bg = pq[v].back();
        frm = v;
    }
    for (pii &u : G[v]) {
        if (dt[u.s] > TT &&!seen[u.f]) {
            dfs(u.f, TT);
        }
    }
}

signed main(){
    IOS();

    cin>>n>>m>>q;
    memset(dt, 0x3f, sizeof dt);
    for (int i = 0; i<n; ++i) {
        cin>>val[i];
    }
    for (int i = 0; i<m; ++i) {
        int a,b; cin>>a>>b; --a; --b;
        g[a].pb({b,i});
        g[b].pb({a,i});
        A[i] = a; B[i] = b;
    }
    int NOWT = 0;
    vector<pii> vt; // vertex, time
    vector<int> dat;
    for (int cnt = 0; cnt<q; ++cnt) {
        int tp; cin>>tp;
        if (tp == 1) {
            int v; cin>>v;
            vt.pb({v-1,NOWT});
        }else{
            NOWT++;
            int e; cin>>e;
            --e;
            dat.pb(e);
            dt[e] = NOWT; // only available for ppl < NOWT
        }
        bool added = 0;
        if (cnt == q-1 && tp != 2) ++NOWT, added = 1;
        if ((tp == 2 && NOWT % BS == 0) || cnt == q-1) {
            bug(cnt, "START");
            if (SZ(vt) == 0) continue;
            // gogogogo
            int NCOL = 1;
            memset(col, 0, sizeof col);

            for (int i = 0; i<n; ++i){
                if (col[i] == 0) {
                    pq[NCOL].clear();
                    dcol(i, NCOL ++, NOWT-1);
                }
            }

            bug(NCOL);

            for (int i = 1; i<NCOL; ++i) {
                sort(ALL(pq[i]));
            }

                bug(SZ(pq[0]));
            vector<int> hv;
            set<pii> sen;
            for (int i = vt[0].s; i<NOWT-added; ++i) {
                if (sen.count({col[A[dat[i]]], col[B[dat[i]]]})) continue;
                G[col[A[dat[i]]]].pb({col[B[dat[i]]],dat[i]});
                G[col[B[dat[i]]]].pb({col[A[dat[i]]],dat[i]});
                hv.pb(col[A[dat[i]]]);
                hv.pb(col[B[dat[i]]]);
                sen.insert({col[A[dat[i]]], col[B[dat[i]]]});
            }
            SORT_UNIQUE(hv);
//            continue;
            for (pii & p : vt) {
                bug(p.f, col[p.f]);
                bg=0; frm = -1;
                dfs(col[p.f], p.s);
                cout<<bg<<endl;
                if (bg != 0) {
                    pq[frm].pop_back(); dead[bg] = 1;
                }
                for (int &x : hv) seen[x] = 0;
//                touch.clear();
            }
            for(int y : hv) G[y].clear();
            vt.clear();
        }
    }

}

#include <bits/stdc++.h>

using namespace std;

int n, m, q, p[200011];

struct Edge {
	int u, v;
} e[300011];

struct oper {
	int opt, s, sma;
	bool tree;
} ques[500011];

bool del[300011];

namespace Sets {
	int fa[200011], siz[200011];
	int find(int w) {
		if(w == fa[w]) return w;
		return fa[w] = find(fa[w]);
	}
	void merge(int x, int y) {
		int fx = find(x), fy = find(y);
		siz[fy] += siz[fx]; fa[fx] = fy;
	}
}

namespace Graph {
	struct edge {
		int u, v, nxt;
		bool flag;
	} a[600011];
	int tot, fir[200011];
	void addedge(int from, int to) {
		a[++tot].u = from;
		a[tot].v = to;
		a[tot].nxt = fir[from];
		a[tot].flag = 1;
		fir[from] = tot;
	}
	void deledge(int w) {
		a[w*2].flag = 0;
		a[w*2+1].flag = 0;
	}
	vector <pair<int, int> > b[200011];
	int cnt, belong[200011], siz[200011], End[200011];
	void dfs1(int w) {
		belong[w] = cnt; siz[cnt]++; End[cnt] = siz[cnt];
		b[cnt].push_back(make_pair(p[w], w));
		int now = fir[w];
		while(now) {
			if(!belong[a[now].v]) dfs1(a[now].v);
			now = a[now].nxt;
		}
	}
	void dfs2(int w) {
		belong[w] = cnt; siz[cnt]++; End[cnt] = siz[cnt];
		b[cnt].push_back(make_pair(p[w], w));
		int now = fir[w];
		while(now) {
			if(a[now].flag == 1 && belong[a[now].v] != cnt)
				dfs2(a[now].v);
			now = a[now].nxt;
		}
	}
	int query(int w) {
		while(End[w] > 0 && belong[b[w][End[w]-1].second] != w) End[w]--;
		if(End[w] < 1) return 0;
		int ret = b[w][End[w]-1].first;
		p[b[w][End[w]-1].second] = 0;
		End[w]--;
		return ret;
	}
}

void print() {
	for(int i = 1; i <= Graph::cnt; i++) {
		cout << i << ":" << endl;
		for(int j = 0; j < Graph::siz[i]; j++) {
			cout << Graph::b[i][j].second << " " << Graph::b[i][j].first << endl;
		}
	}
	cout << "belongs:";
	for(int i = 1; i <= n; i++)
	cout << Graph::belong[i] << " "; cout << endl;
}

int main() {
	scanf("%d%d%d", &n, &m, &q);
	Graph::tot = 1; Graph::cnt = 0;
	memset(Graph::belong, 0, sizeof(Graph::belong));
	memset(Graph::fir, 0, sizeof(Graph::fir));
	for(int i = 1; i <= n; i++)
		scanf("%d", &p[i]), Sets::fa[i] = i;
	for(int i = 1; i <= m; i++) {
		scanf("%d%d", &e[i].u, &e[i].v);
		Graph::addedge(e[i].u, e[i].v);
		Graph::addedge(e[i].v, e[i].u);
	}
	for(int i = 1; i <= q; i++) {
		scanf("%d%d", &ques[i].opt, &ques[i].s);
		if(ques[i].opt == 2) del[ques[i].s] = 1;
	}
	for(int i = 1; i <= m; i++)
		if(!del[i]) Sets::merge(e[i].u, e[i].v);
	for(int i = q; i >= 1; i--) {
		if(ques[i].opt == 2) {
			int x = e[ques[i].s].u, y = e[ques[i].s].v;
			if(Sets::find(x) == Sets::find(y)) ques[i].tree = 0;
			else {
				ques[i].tree = 1;
				if(Sets::siz[x] < Sets::siz[y]) ques[i].sma = x;
				else ques[i].sma = y;
				Sets::merge(x, y);
			}
		}
	}
	for(int i = 1; i <= n; i++) {
		if(!Graph::belong[i]) {
			Graph::cnt++;
			Graph::dfs1(i);
		}
	}
	//for(int i = 1; i <= n; i++)
	//	cout << Graph::belong[i] << " "; cout << endl;
	for(int i = 1; i <= Graph::cnt; i++)
		sort(Graph::b[i].begin(), Graph::b[i].end());
	/*for(int i = 1; i <= Graph::cnt; i++) {
		cout << i << ":" << endl;
		for(int j = 0; j < Graph::siz[i]; j++) {
			cout << Graph::b[i][j].second << " " << Graph::b[i][j].first << endl;
		}
	}*/
	//return 0;
	for(int i = 1; i <= q; i++) {
		if(ques[i].opt == 1) {
			int bel = Graph::belong[ques[i].s];
			printf("%d\n", Graph::query(bel));
		}
		else {
			//continue;
			//cout << e[ques[i].s].u << "--" << e[ques[i].s].v << endl;
			Graph::deledge(ques[i].s);
			if(ques[i].tree == 0) continue;
			int x = e[ques[i].s].u, y = e[ques[i].s].v;
			//cout << "tree edge" << endl;
			Graph::cnt++;
			Graph::dfs2(ques[i].sma);
			//print();
		}
	}
	return 0;
}

#include <bits/stdc++.h>

using namespace std;
#define sim template < class c
#define ris return * this
#define dor > debug & operator <<
#define eni(x) sim > typename \
  enable_if<sizeof dud<c>(0) x 1, debug&>::type operator<<(c i) {
sim > struct rge { c b, e; };
sim > rge<c> range(c i, c j) { return rge<c>{i, j}; }
sim > auto dud(c* x) -> decltype(cerr << *x, 0);
sim > char dud(...);
struct debug {
#ifndef LOCAL
~debug() { cerr << endl; }
eni(!=) cerr << boolalpha << i; ris; }
eni(==) ris << range(begin(i), end(i)); }
sim, class b dor(pair < b, c > d) {
  ris << "(" << d.first << ", " << d.second << ")";
}
sim dor(rge<c> d) {
  *this << "[";
  for (auto it = d.b; it != d.e; ++it)
	*this << ", " + 2 * (it == d.b) << *it;
  ris << "]";
}
#else
sim dor(const c&) { ris; }
#endif
};
#define imie(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef pair<long long, int> pli;
typedef long long ll;
#define f first
#define s second
#define endl '\n'
#define all(x) x.begin(),x.end()
const int N=5e5+1;
int p[ N ],tin [ N ],tout[ N ],timer;
int get( int v ){
    return p[v] = ( v == p[v] ? v : get( p[ v ] ) );
}
int n,m,q;
vector<int> g [ N ];
pii t[ 4*N ];
int a[ N ];
int obr[N];
void mg(int a, int b){
    int c = get( a ), d = get( b );
    if(c == d) return;
    n++;
    p[c]=n;
    p[d]=n;
    g[ n ].emplace_back(c);
    g[ n ].emplace_back(d);
    return ;
}
void dfs(int v, int p){
    tin[ v ] = timer++;
    obr[ timer - 1 ] = v;
    for(auto &z : g[ v ]){
//        if(z == p) continue;
        dfs( z, v );
    }
    tout[ v ] = timer - 1;
}
void b_tr(int v,int tl,int tr){
    if(tl == tr){
        t[v]={a[obr[tl]],tl};
    }
    else{
        int tm=(tl+tr)>>1;
        b_tr(2*v,tl,tm);
        b_tr(2*v+1,tm+1,tr);
        t[v]=max(t[2*v],t[2*v+1]);
    }
}
pii getMax(int l,int r,int v,int tl,int tr){
    if(tl>=l && tr<=r){
        return t[v];
    }
    if(tl>r || tr<l) return {0,n};
    int tm=(tl+tr)>>1;
    return max(getMax(l,r,2*v,tl,tm),getMax(l,r,2*v+1,tm+1,tr));
}
void upd(int id,int v,int tl,int tr){
    if(tl==tr){
        t[v].first=0;
        return ;
    }
    int tm=(tl+tr)>>1;
    if(tm>=id)
        upd(id,2*v,tl,tm);
    else
        upd(id,2*v+1,tm+1,tr);
    t[v]=max(t[2*v],t[2*v+1]);
}
pii e[N];
bool ex[N];
pii qe[N];
signed main(){
    cin.tie(0);cout.tie(0);ios_base::sync_with_stdio(false);
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i = 0;i < m;i++){
        int v,u;
        cin>>v>>u;
        e[i]={v,u};
    }
    iota(p,p+N,0);
    for(int i = 0;i < q;i++){
        int tp;
        cin>>tp;
        int id;
        cin>>id;
        if(tp==2){
            ex[id-1]=1;
        }
        qe[i]={tp,id};
    }
    for(int i = 0; i < m;i++){
        if(!ex[i]){
            mg(e[i].f,e[i].s);
//            for(int i = 1;i <= n; i++){
////                debug()<<imie(get(i));
//            }
//            cout<<endl;
        }
    }
    for(int i = q - 1; ~ i; --i){
        if(e[i].f==2)
            mg(e[qe[i].s-1].f,e[qe[i].s-1].s);
        else {

//            debug()<<imie(qe[i].s)imie(get(qe[i].s));
            qe[i].s=get(qe[i].s);
        }
    }
    for(int i = 1;i <= n; i++){
        if(get(i)==i)
            dfs(i,i);
    }
    b_tr(1,1,n);
//    for(int i = 1;i <= n; i++){
//        debug()<<imie(tin[i])imie(tout[i])imie(getMax(tin[i],tin[i],1,1,n))imie(a[i]);
//    }
//    vector<int> ans;
    for(int i = i=0; i<q; i++){
        if(qe[i].f==1){
            int id=qe[i].s;
            auto w=getMax(tin[id],tout[id],1,1,n);
            upd(w.s,1,1,n);
//            debug()<<imie(w)imie(id);
            cout<<w.f<<endl;
        }
    }
//    reverse(all(ans));
//    for(auto &z : ans) cout<<z<<endl;
    return 0;
}

#include <stdio.h>
#include <bits/stdc++.h>

using namespace std;

const int N = 200005;
const int M = 300005;
const int Q = 500005;

int n, m, q, ori;
int ea[M], eb[M], er[N];
int type[Q], qu[Q];
int c[N+N];
int dup[N+N][20];
int par[N+N];

vector<int> g[N+N];
int in[N+N], out[N+N], dfs_t;

void dfs(int u) {
	if(u <= ori) {
		in[u] = ++dfs_t;
		out[u] = dfs_t;
		return;
	}
	in[u] = -1;
	for(int v : g[u]) {
		dfs(v);
		if(in[u] == -1) in[u] = in[v];
	}
	out[u] = dfs_t;
}

int f(int u) {
	return u == par[u] ? u : par[u] = f(par[u]);
}

int get_root(int u, int ti) {

	for(int j = 19; j >= 0; j--) {
		if(c[ dup[u][j] ] >= ti) {
			u = dup[u][j];
		}
	}
	return u;
}

pair<int, int> st[4*N];

void upd(int i, int val, int p, int L, int R) {
	if(i < L or i > R) return;
	if(L == R) {
		st[p] = {val, L};
		return;
	}
	int mid = (L + R) / 2;
	upd(i, val, 2 * p, L, mid);
	upd(i, val, 2 * p + 1, mid + 1, R);
	st[p] = max(st[2 * p], st[2 * p + 1]);
}
pair<int, int> query(int i, int j, int p, int L, int R) {
	if(j < L or i > R) return {-1, -1};
	if(L >= i and R <= j) return st[p];
	int mid = (L + R) / 2;
	return max(query(i, j, 2 * p, L, mid), query(i, j, 2 * p + 1, mid + 1, R));
}
int p[N];

int main() {
	scanf("%d %d %d", &n, &m, &q);
	ori = n;

	for(int i = 1; i <= n; i++) scanf("%d", p + i);

	for(int i = 1; i <= m; i++) {
		scanf("%d %d", ea + i, eb + i);
	}

	for(int i = 0; i < q; i++) {
		scanf("%d %d", type + i, qu + i);
		if(type[i] == 2) er[ qu[i] ] = 1;
	}

	for(int i = 1; i <= n; i++) par[i] = i, c[i] = q;

	for(int i = 1; i <= m; i++) if(!er[i]) {
		int a = f(ea[i]), b = f(eb[i]);
		if(a == b) continue;
		++n;
		dup[a][0] = dup[b][0] = n;
		par[a] = par[b] = par[n] = n;
		c[n] = q;
		g[n].push_back(a);
		g[n].push_back(b);
	}

	for(int i = q - 1; i >= 0; i--) if(type[i] == 2) {
		int a = f(ea[ qu[i] ]), b = f(eb[ qu[i] ]);
		if(a == b) continue;
		++n;
		dup[a][0] = dup[b][0] = n;
		par[a] = par[b] = par[n] = n;
		c[n] = i;
		g[n].push_back(a);
		g[n].push_back(b);
	}

	for(int i = 2; i <= ori; i++) if(f(i) != f(1)) {
		int a = f(1), b = f(i);
		++n;
		dup[a][0] = dup[b][0] = n;
		par[a] = par[b] = par[n] = n;
		c[n] = -1;
		g[n].push_back(a);
		g[n].push_back(b);
	}

	dup[n][0] = n;

	for(int lvl = 0; lvl + 1 < 20; lvl++) {
		for(int i = 1; i <= n; i++) {
			dup[i][lvl + 1] = dup[ dup[i][lvl] ][lvl];
		}
	}

	dfs(n);

	for(int i = 1; i <= ori; i++) {
		upd(in[i], p[i], 1, 1, ori);
	}

	for(int i = 0; i < q; i++) {
		if(type[i] == 1) {
			int r = get_root(qu[i], i);
			auto [val, id] = query(in[r], out[r], 1, 1, ori);
			printf("%d\n", val);
			upd(id, 0, 1, 1, ori);
		}
	}
}

// Expected verdict: Wrong Answer
// But this does surprisingly well against random test cases,
// and may pass if systests are weak, even though it is rubbish

#include <iostream>
#include <cassert>
#include <vector>
#include <queue>
#include <algorithm>

using VI = std::vector<int>;

struct ST {
  VI& src;
  VI arr;
  int p2;

  int imax(int i, int j) {
    return (src[i] == src[j] ? i > j : src[i] > src[j]) ? i : j;
  }

  void update(int L, int R) {
    L = (L + p2) >> 1;
    R = (R + p2 + 1) >> 1;
    while (L) {
      for (int i = L; i < R; ++i)
        arr[i] = imax(arr[2*i], arr[2*i+1]);
      L = L >> 1;
      R = (R + 1) >> 1;
    }
    return;
  }

  void update(int ix) {
    ix = (ix + p2) >> 1;
    while (ix) {
      arr[ix] = imax(arr[2*ix], arr[2*ix+1]);
      ix >>= 1;
    }
    return;
  }

  ST(VI& _src)
    :src { _src }
  {
    int n = int(src.size());
    assert(n % 2 == 0);
    for (p2 = 1; p2 < n; p2 <<= 1)
      ;
    arr = VI(n + p2, n-1);
    for (int i = 0; i < n; ++i)
      arr[i + p2] = i;
    update(0, n);
  }

  int rmq(int L, int R) {
    int ans = L;
    L += p2;
    R += p2;
    while (L < R) {
      ans = imax(ans, arr[L]);
      ans = imax(ans, arr[R-1]);
      L = (L + 1) >> 1;
      R >>= 1;
    }
    return ans;
  }
};

int main() {
  using namespace std;
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n, m, q;
  cin >> n >> m >> q;
  VI p = VI(n+1);
  for (int i = 1; i <= n; ++i)
    cin >> p[i];

  struct UE { // Undirected Edge
    int priority;
    int u;
    int v;
  };

  vector<UE> edges = vector<UE>(m+1);
  for (int i = 1; i <= m; ++i) {
    int u, v;
    cin >> u >> v;
    edges[i].priority = q + i;
    edges[i].u = p[u];
    edges[i].v = p[v];
  }

  struct Query {
    int priority;
    int v;
  };
  vector<Query> queries;
  queries.reserve(q);
  for (int i = 1; i <= q; ++i) {
    int t, v;
    cin >> t >> v;
    if (t == 1)
      queries.push_back(Query { i, v });
    else
      edges[v].priority = i;
  }

  struct E { // Edge
    int priority;
    int oSide;

    bool operator < (E o) const {
      return priority < o.priority;
    }
  };

  vector<vector<E>> gr = vector<vector<E>>(n+1);
  for (UE e : edges) {
    gr[e.u].push_back(E { e.priority, e.v });
    gr[e.v].push_back(E { e.priority, e.u });
  }
  for (Query cq : queries)
    gr[cq.v].push_back(E { cq.priority, -1 });

  struct QueryInterval {
    int priority;
    int start;
    int stop;
  };
  vector<int> vertexLabels;
  vertexLabels.reserve(n + n % 2);
  vector<QueryInterval> qis;
  qis.reserve(queries.size());

  { // calculate vertexLabels, qis
    priority_queue<E> pq;
    for (int i = 1; i <= n; ++i)
      pq.push(E { 0, i });
    vector<char> vis = vector<char>(n+1, char(false));

    struct PStackObj {
      int priority;
      int start;
    };
    vector<PStackObj> stack;

    while (!pq.empty()) {
      E e = pq.top();
      pq.pop();
      while (!stack.empty() && stack.back().priority >= e.priority)
        stack.pop_back();
      if (e.oSide == -1) { // vertex query
        assert(!stack.empty());
        qis.push_back(QueryInterval {
            e.priority, stack.back().start, int(vertexLabels.size()) });
      }
      else { // real edge: follow
        if (vis[e.oSide])
          continue;
        vis[e.oSide] = char(true);
        stack.push_back(PStackObj { e.priority, int(vertexLabels.size()) });
        vertexLabels.push_back(e.oSide);
        for (E e2 : gr[e.oSide])
          pq.push(e2);
      }
    }
    assert(int(vertexLabels.size()) == n);
    if (n % 2)
      vertexLabels.push_back(vertexLabels.back());
  }

  ST st { vertexLabels };
  sort(qis.begin(), qis.end(), [](QueryInterval qi1, QueryInterval qi2) {
      return qi1.priority < qi2.priority;
    });
  for (QueryInterval cqi : qis) {
    int i = st.rmq(cqi.start, cqi.stop);
    assert(0 <= i);
    assert(i < n);
    cout << vertexLabels[i] << endl;
    vertexLabels[i] = 0;
    st.update(i);
  }

  return 0;
}

#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization ("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(auto i = (a); i < (b); i++)
#define pb push_back
#define fs first
#define sc second
typedef long long ll;
typedef pair<int,int> ii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ii> vii;
typedef vector<vii> vvii;

const double EPS = 1e-9;

typedef pair<int,ii> T;

set<ii> BST[200'050];
struct union_find {
	vi p;
    vi sz;
    vi A;

    vector<unordered_set<int>> BACK;

	union_find(int n, vi &b) : A(b), p(n), sz(n,1), BACK(n,unordered_set<int>()) {
        rep(i,0,n) p[i] = i;
        rep(i,0,n) BST[i].insert(ii(A[i],i));
    }

    stack<T> q;
    int cur = 0;

	int find(int a) {
        if(a == p[a]) return a;
        return find(p[a]);
    }

    int best(int a) {
        a = find(a);
        if(BST[a].size() == 0) return 0;
        ii val = *(--BST[a].end());
        BST[a].erase(val);
        A[val.sc] = 0;
        return val.fs;
    }

	bool joined(int a, int b) {
        return find(a) == find(b);
    }

    void change(int at, int from, int to) {
        if(A[at] != 0) {
            BST[from].erase(ii(A[at],at));
            BST[to].insert(ii(A[at],at));
        }
        for(auto a : BACK[at]) {
            change(a, from, to);
        }
    }

    void change_forward(int from, int to) {
        for(auto a : BST[from]) {
            BST[to].insert(a);
        }
    }

	void unite(int a, int b) {

        a = find(a);
        b = find(b);
        if(a == b) {
            q.push(T(-1,ii(0,0)));
            return;

        }

        if(sz[a] < sz[b]) {
            // go through smaller size remove and add to other
            change_forward(a, b);

            sz[b] += sz[a];

            q.push( T(cur, ii(a, p[a])) );
            BACK[b].insert(a);

            p[a] = b;

        } else {
            change_forward(b, a);

            sz[a] += sz[b];
            q.push( T(cur, ii(b, p[b])) );

            BACK[a].insert(b);

            p[b] = a;

        }
    }

    void pop() {
        T a = q.top();
        q.pop();
        if(a.fs == -1) return;
        int top = find(a.sc.fs);
        change(a.sc.fs, top, a.sc.fs);
        BACK[top].erase(a.sc.fs);
        sz[top] -= sz[a.sc.fs];
        p[a.sc.fs] = a.sc.sc;
    }
};

int main() {
    cin.sync_with_stdio(false);
    int n,m,q;
    cin >> n >> m >> q;

    vi A(n);
    rep(i,0,n) cin >> A[i];
    vii E;
    rep(i,0,m) {
        int u,v;
        cin >> u >> v;
        u--;v--;
        E.pb(ii(u,v));
    }
    union_find un(n, A);

    vii OP(q);
    rep(i,0,q) cin >> OP[i].fs >> OP[i].sc;
    vi IS_REM(m,0);
    for(int i = q-1; i >= 0; i--) {
        if(OP[i].fs == 2) {
            IS_REM[OP[i].sc-1] = 1;
        }
    }
    rep(i,0,m) {
        if(!IS_REM[i]) {
            un.unite(E[i].fs, E[i].sc);
        }
    }
    for(int i = q-1; i >= 0; i--) {
        if(OP[i].fs == 2) {
            un.unite(E[OP[i].sc-1].sc, E[OP[i].sc-1].fs);
        }
    }
    for(int i = 0; i < q; i++) {
        if(OP[i].fs == 1) {
            int val = un.best(OP[i].sc-1);
            cout << val << endl;
        } else {
            un.pop();
        }
    }
}

#include<bits/stdc++.h>
using namespace std;
#define I inline int
#define V inline void
#define ll long long int
#define isnum(ch) ('0'<=ch&&ch<='9')
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ROF(i,a,b) for(int i=a;i>=b;i--)
#define REP(u) for(int i=h[u],v;v=e[i].t,i;i=e[i].n)
#define gc (_op==_ed&&(_ed=(_op=_buf)+fread(_buf,1,100000,stdin),_op==_ed)?EOF:*_op++)
char _buf[100000],*_op(_buf),*_ed(_buf);
I getint(){
	int _s=0,_f=1;char _ch=gc;
	while(!isnum(_ch))(_ch=='-')&&(_f=-1),_ch=gc;
	while(isnum(_ch))_s=_s*10+_ch-48,_ch=gc;
	return _s*_f;
}
const int N=3e5+2,INF=0x3f3f3f3f;
set<int>mp[N];
int T,n,m,q,ans;
int w[N],a[N],b[N],id[N];
int fa[N],siz[N],tag[N];
int opt[N],val[N],dis[N][2];
vector<int>cha[N],now[N];
V input(){
	n=getint(),m=getint(),q=getint();
	FOR(i,1,n)w[i]=getint(),id[w[i]]=i;
	FOR(i,1,m)a[i]=getint(),b[i]=getint(),tag[i]=1;
	FOR(i,1,q)opt[i]=getint(),val[i]=getint();
}
V merge(int x,int y){
	if((x=fa[x])==(y=fa[y]))return;
	if(siz[x]<siz[y])swap(x,y);
	for(int v:now[y])now[x].push_back(v),fa[v]=x;
	siz[x]+=siz[y];
}
V init(int x=0,int y=0){
	FOR(i,1,n)fa[i]=i,siz[i]=1,now[i].push_back(i);
	FOR(i,1,q)if(opt[i]==2)tag[val[i]]=0;
	FOR(i,1,m)if(tag[i])merge(a[i],b[i]);
	ROF(i,q,1)if(opt[i]==2){
		x=a[val[i]],y=b[val[i]];
		if((x=fa[x])==(y=fa[y]))continue;
		if(siz[x]<siz[y])swap(x,y);
		for(int v:now[y])now[x].push_back(y),fa[v]=x;
		fa[y]=x,siz[x]+=siz[y],dis[i][0]=x,dis[i][1]=y;
	}
	FOR(i,1,n)mp[fa[i]].insert(w[i]);
}
V work(){
	int x,y,p;
	FOR(i,1,q)
		if(opt[i]==1){
			x=fa[val[i]];
			p=*--mp[x].end();
			cout<<p<<'\n';
			w[id[p]]=0;
			mp[x].erase(p);
			mp[x].insert(0);
		}
		else if(dis[i][0]){
			x=dis[i][0],y=dis[i][1];
			FOR(j,1,siz[y])
				now[x].pop_back();
			siz[x]-=siz[y];
			for(int v:now[y]){
				fa[v]=y,mp[y].insert(w[v]);
				if(mp[x].find(w[v])!=mp[x].end())mp[x].erase(w[v]);
			}
			mp[x].insert(0);
		}
}
int main(){
//	freopen("test.in","r",stdin);
//	freopen(".out","w",stdout);
//	for(scanf("%d",&T);T--;){
		input();
		init();
		work();
//	}
	return 0;
}

#include <bits/stdc++.h>
//#include "race.h"
//    #pragma GCC optimize("-O3")
//    #pragma GCC optimize("no-stack-protector")
//    #pragma GCC optimize("fast-math")
//    #pragma GCC optimize("Ofast")
//    #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx")
//    #pragma GCC target("avx,avx2,fma")
//    #pragma GCC optimization ("unroll-loops")
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define fi first
#define f first
#define s second
#define se second
#define vec vector
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define pb push_back
#define sz(x) (int)x.size()
#define pw(x) (1ll<<x)
#define p_b push_back
#define m_p make_pair
#define fast_io ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define sq(x) (x)*(x)
//#define int long long
using namespace std;
using namespace __gnu_pbds;
typedef pair<long long, long long> PII;
typedef pair<int, int> pii;
typedef long double ld;
typedef long long ll;
typedef pair<long long, long long > pll;
template <typename T> umax(T &a, T b){return (a<b ? a=b,1 : 0);}
template <typename T> umin(T &a, T b){return (a>b ? a=b,1 : 0);}
typedef tree<pii,null_type,less<pii>,rb_tree_tag,tree_order_statistics_node_update> o_set;
const int N=2e5+5;
const ll inf=1e9;
const ld eps = 1e-9;
const int ppp=73;
const int M=99999837;
const ll tx[4]={-1,1,0,0};
const ll ty[4]={0,0,-1,1};
const char rev_to[4]={'U','D','L','R'};
auto rnd=bind(uniform_int_distribution<ll>(1,1e9),mt19937(time(0)));
int n,m,q;
int p[N],in[N],out[N],obr[N],t;
vec<int> g[N];
void make(int v){
    p[v]=v;
}
int get(int v){
    return p[v]=(p[v]==v?v:get(p[v]));
}
void mg(int a,int b){
    int c=get(a),d=get(b);
    if(c==d){
        return;
    }
    p[c]=++n;
    p[d]=n;
    g[n].pb(c);
    g[n].pb(d);
}
struct seg{
    pii t[4*N];
    void init(){
        fill(t,t+4*N,m_p(0,0));
    }
    void upd(int v,int tl,int tr,int id, pii vl){
        if(tl==tr){
            t[v]=vl;
            return;
        }
        int tm=(tl+tr)>>1;
        if(tm>=id)
            upd(2*v,tl,tm,id,vl);
        else
            upd(2*v+1,tm+1,tr,id,vl);
        t[v]=max(t[2*v],t[2*v+1]);
    }
    pii get(int l,int r,int v,int tl,int tr){
        if(tl>=l && tr<=r){
            return t[v];
        }
        if(tl>r || tr<l){
            return {0,0};
        }
        int tm=(tl+tr)>>1;
        return max(get(l,r,2*v,tl,tm),
                   get(l,r,2*v+1,tm+1,tr));
    }
}Do;
int a[N];
pii e[N];
bool used[N];
void dfs(int v){
    in[v]=++t;
    obr[t]=v;
    for(auto &z : g[v]){
        if(!in[z])
            dfs(z);
    }
    out[v]=t;
}
signed main()
{
    fast_io;
//    ifstream cin("numpalindrome.in");
//    ofstream cout("numpalindrome.out");
    cin>>n>>m>>q;
    for(int i = 1; i<=n;i++){
        cin>>a[i];
    }
    for(int i = 0 ; i < m; ++i){
        int v,u;
        cin>>v>>u;
        e[i]={v,u};
    }
    vec<pii>zapr(q);
    for(int i = 0; i < q; ++i){
        cin>>zapr[i].f>>zapr[i].s;
        if(zapr[i].f==1){

        }
        else{
            zapr[i].s--;
            used[zapr[i].s]=1;
        }
    }
    for(int i = 1; i < N; ++i)
        make(i);
    for(int i = q - 1 ; ~i; --i){
        if(zapr[i].f==1){
            int x=get(zapr[i].s);
            zapr[i].s=x;
        }
        else{
            mg(e[zapr[i].s].f,e[zapr[i].s].s);
        }
    }
    for(int i = 1; i <= n; i ++){
        if(get(i)==i){
            dfs(i);
        }
    }
    for(int i = 1; i <= n; i++){
        Do.upd(1,1,n,in[i],{a[i],in[i]});
    }
    for(int i = 0; i < q; i++){
        if(zapr[i].f==1){
            int x=zapr[i].s;
            pii c=Do.get(in[x],out[x],1,1,n);
            Do.upd(1,1,n,c.s,{0,c.s});
            cout<<c.f<<"\n";
        }
    }
    return 0;
}
/*
(3a(b(4c)))
*/

#include<bits/stdc++.h>
using namespace std;
pair<int,int> st[800005],tv[500005],c[500005];
int f[200005],f2[200005],n,m,q,nx[200005],l[200005],r[200005],cnt,cnt2,u,v,x[200005],p[200005],cs[200005],deg[200005],vt[200005],L,R;
vector<int> vec[200005];
bool kt[300005];
set<int> s;
set<int> :: iterator it;
void up(int id,int l,int r,int vt,int gt)
{
    if (l>r || l>vt || r<vt) return;
    if (l==r)
    {
        st[id]={gt,vt};
        return;
    }
    int mid=(l+r)/2;
    up(id*2,l,mid,vt,gt);
    up(id*2+1,mid+1,r,vt,gt);
    st[id]=max(st[id*2],st[id*2+1]);
}
pair<int,int> get(int id,int l,int r,int u,int v)
{
    if (l>r || l>v || r<u) return {0,0};
    if (l>=u && r<=v) return st[id];
    int mid=(l+r)/2;
    return max(get(id*2,l,mid,u,v),get(id*2+1,mid+1,r,u,v));

}
int phin(int u)
{
    return f[u]<0 ? u : f[u]=phin(f[u]);
}
void uni(int u,int v)
{
    if (f[u]>f[v]) swap(u,v);
    f[u]+=f[v];
    f[v]=u;
}
int phin2(int u)
{
    return f2[u]<0 ? u : f2[u]=phin(f2[u]);
}
void uni2(int u,int v,int i)
{
    if (f2[u]>f2[v]) swap(u,v);
    nx[r[u]]=l[v];
    deg[l[v]]++;
    x[r[u]]=i;
    r[u]=r[v];
    f2[u]+=f2[v];
    f2[v]=u;
}
int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>m>>q;bool db=false;
    if (n==96 && m==141 & q==151) db=true;
    for (int i=1;i<=n;++i) cin>>p[i];
    memset(f,-1,sizeof(f));
    for (int i=1;i<=m;++i) cin>>c[i].first>>c[i].second;
    for (int i=1;i<=q;++i)
     {
         cin>>tv[i].first>>tv[i].second;
         if (tv[i].first==2) kt[tv[i].second]=true;
     }
    for (int i=1;i<=m;++i)
     if (!kt[i])
    {
        u=c[i].first;
        v=c[i].second;
        u=phin(u);
        v=phin(v);
        if (u!=v) uni(u,v);
    }
    for (int i=1;i<=n;++i)
     if (i==phin(i)) {++cnt;l[cnt]=r[cnt]=cnt;cs[i]=cnt;}
    for (int i=1;i<=n;++i)
     vec[cs[phin(i)]].push_back(i);
    memset(f2,-1,sizeof(f2));
    for (int i=q;i>0;--i)
     if (tv[i].first==2)
    {
        u=c[tv[i].second].first;
        v=c[tv[i].second].second;
        u=cs[phin(u)];
        v=cs[phin(v)];
        u=phin2(u);
        v=phin2(v);
        if (u!=v) uni2(u,v,i);
    }
    memset(cs,0,sizeof(cs));
    s.insert(0);

    for (int i=1;i<=cnt;++i)
     if (deg[i]==0)
    {
        u=i;
        while (1)
        {
            for (int j=0;j<vec[u].size();++j) {++cnt2;up(1,1,n,cnt2,p[vec[u][j]]);vt[vec[u][j]]=cnt2;}
            if (nx[u])
             {
                 cs[x[u]]=cnt2;
                 u=nx[u];
             }
             else break;
            if (cnt2>n) {cout<<-1;return 0;}
        }
        s.insert(cnt2);

    }

    for (int i=1;i<=q;++i)
    {
        if (tv[i].first==1)
        {
           it=s.lower_bound(vt[tv[i].second]);
           R=(*it);
           it--;
           L=(*it)+1;
           pair<int,int> X=get(1,1,n,L,R);
           cout<<X.first<<'\n';
           up(1,1,n,X.second,0);
        }
        else s.insert(cs[i]);
    }

    return 0;
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#define mp make_pair
#define fi first
#define se second
#define pb push_back
#define ls (x<<1)
#define rs (x<<1|1)
#define db double
#define inf 2147483647
#define llinf 9223372036854775807
#define ll long long
#define ull unsigned long long
using namespace std;
typedef pair<int,int> PII;
int inline read(){
    int num=0,neg=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')neg=-1;c=getchar();}
    while(isdigit(c)){num=(num<<3)+(num<<1)+c-'0';c=getchar();}
    return num*neg;
}
const int maxn=500010,mod=998244353;
int n,m,q,p[maxn],cnt,fa[maxn],tot;
struct Q{
	int t,x;
}a[maxn];
struct Edge{
	int u,v,w;
}edge[maxn];
bool cmp(Edge x,Edge y){
	return x.w>y.w;
}
int Find(int x){
	return fa[x]==x?x:fa[x]=Find(fa[x]);
}vector<int>G[maxn];int val[maxn];
void kruskal(){
	for(int i=1;i<=2*n;i++)fa[i]=i;tot=n;
	for(int i=1;i<=m;i++){
		int x=Find(edge[i].u),y=Find(edge[i].v);
		if(x!=y){
			++tot;fa[x]=fa[y]=tot;val[tot]=edge[i].w;
			G[tot].pb(x);G[tot].pb(y);
		}
	}++tot;
	for(int i=1;i<tot;i++)
		if(fa[i]==i)G[tot].pb(i);
}int dfn[maxn],c,rev[maxn],L[maxn],R[maxn],jmp[maxn][21],dep[maxn];
void dfs(int x){
	for(int i=1;i<=20;i++)jmp[x][i]=jmp[jmp[x][i-1]][i-1];
	if(!G[x].size()){
		dfn[x]=++c;rev[c]=x;L[x]=c;R[x]=c;return;
	}L[x]=inf;R[x]=0;
	for(int i=0;i<G[x].size();i++){
		int v=G[x][i];dep[v]=dep[x]+1;jmp[v][0]=x;dfs(v);
		L[x]=min(L[x],L[v]);R[x]=max(R[x],R[v]);
	}
}
int sum[maxn<<2],pos[maxn<<2];
void pushup(int x){
	if(sum[ls]>sum[rs])pos[x]=pos[ls];
	else pos[x]=pos[rs];
	sum[x]=max(sum[ls],sum[rs]);
}
void update(int x,int l,int r,int P,int k){
	if(l==r){
		sum[x]=k;pos[x]=rev[l];return;
	}int mid=l+r>>1;
	if(mid>=P)update(ls,l,mid,P,k);
	if(mid<P)update(rs,mid+1,r,P,k);pushup(x);
}
int Query(int x,int l,int r,int L,int R){
	if(l>=L&&r<=R)return pos[x];
	int mid=l+r>>1,posl=0,posr=0,ans=0;
	if(mid>=L)posl=Query(ls,l,mid,L,R);
	if(mid<R)posr=Query(rs,mid+1,r,L,R);
	if(p[posl]>=p[ans])ans=posl;
	if(p[posr]>=p[ans])ans=posr;return ans;
}
int main(){
	n=read();m=read();q=read();
	for(int i=1;i<=n;i++)p[i]=read();
	for(int i=1;i<=m;i++){
		int x=read(),y=read();
		edge[i].u=x;edge[i].v=y;edge[i].w=inf;
	}
	for(int i=1;i<=q;i++){
		int op=read(),x=read();
		if(op==1){
			a[++cnt].t=i;a[cnt].x=x;
		}else edge[x].w=i-1;
	}sort(edge+1,edge+m+1,cmp);kruskal();dep[tot]=1;dfs(tot);
	for(int i=1;i<=n;i++)update(1,1,n,dfn[i],p[i]);
	for(int i=1;i<=cnt;i++){
		int now=a[i].x;
		for(int j=20;j>=0;j--)
			if(val[jmp[now][j]]>=a[i].t)now=jmp[now][j];
		int ans=Query(1,1,n,L[now],R[now]);
		printf("%d\n",p[ans]);
		p[ans]=0;update(1,1,n,dfn[ans],p[ans]);
	}return 0;
}

#include <bits/stdc++.h>
#define ll long long
#define endl "\n"
#define pb push_back
#define ms(v,x) memset(v,x,sizeof(v))
#define ff first
#define ss second
#define td(v) v.begin(),v.end()
#define rep(i,a,n) for (int i=(a);i<(n);i++)
#define re(v) {for(auto &_re : v) cin >> _re;}
#define rre(v){for(auto &_re : v) for(auto &_rre : _re) cin >> _rre;}
#define pr(v) {for(auto _pr : v) cout << _pr << " "; cout << endl;}
#define prr(v) {for(auto _prr : v) cout << _prr.ff << " " << _prr.ss << endl;}
#define pii pair<int,int>
#define pll pair<ll,ll>
#define eb emplace_back
using namespace std;
const ll M = 1e9 + 7;
const ll mod = 998244353;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

ll binpow(ll a, ll b, ll m){
  ll res = 1;
  while(b > 0){
    if(b&1) res = res * a % m;
    a = a * a % m;
    b>>=1;
  }
  return res;
}
ll gcd(ll a, ll b){
  return (b==0 ? a : gcd(b,a%b));
}
struct dsu{ // dsu with rollback
	struct op{
		int u, l, t;
		op(){}
		op(int u,int l,int t) : u(u), l(l), t(t){}
	};
	vector<int> pai, tam;
	stack<op> old_pai;
	stack<op> old_tam;
	vector<int> g[200200];
	dsu(){}
	dsu(int n){
		pai.resize(n);
		tam = pai;
		for(int i=0;i<n;i++){
			pai[i] = i;
			tam[i] = 1;
		}
	}
	vector<int> at;
	void init(vector<int> &v){
		at.resize(v.size() + 1);
		for(int i=0;i<v.size();i++){
			g[i].eb(v[i]);
			at[v[i]] = i;
		}
	}
	int find(int u){
		if(pai[u] == u) return u;
		return find(pai[u]);
	}
	void merge(int u, int v, int t){ // merges u and v at time T;
		int a = find(u);
		int b = find(v);
		if(a==b) return;
		if(tam[a] > tam[b]) swap(a, b);
		old_pai.emplace(a, pai[a], t);
		old_tam.emplace(b, tam[b], t);
		pai[a] = b;
		tam[b] += tam[a];
		for(int &x : g[a]){
			g[b].push_back(x);
			at[x] = b;
		}
	}
	void query(int v){
		v = find(v);
		int go = 0;
		while(!g[v].empty()){
			int u = g[v].back();
			g[v].pop_back();
			if(u == 0 or at[u] != v) continue;
			else{
				go = u;
				at[u] = -1;
				break;
			}
		}
		cout << go << endl;
	}
	void rollback(int t){
		while(!old_pai.empty() && old_pai.top().t >= t){ // rolls back until time = t-1
			pai[old_pai.top().u] = old_pai.top().l;
			tam[old_tam.top().u] = old_tam.top().l;
			for(int &x : g[old_pai.top().l]){
				at[x] = old_pai.top().l;
			}
			old_pai.pop();
			old_tam.pop();
		}
	}
};
void solve(){
  int n,m,q;
  cin >> n >> m >> q;
  vector<int> p(n), er(m);
  re(p);
  vector<pii> e(m);
  for(int i=0;i<m;i++){
  	cin >> e[i].ff >> e[i].ss;
  	e[i].ff--; e[i].ss--;
  }
  vector<pii> qs(q);
  for(int i=0;i<q;i++){
  	cin >> qs[i].ff >> qs[i].ss;
  	qs[i].ss--;
  	if(qs[i].ff == 2) er[qs[i].ss] = 1;
  }
  dsu D(n);
  D.init(p);
  for(int i=0;i<m;i++){
  	if(er[i]) continue;
  	D.merge(e[i].ff, e[i].ss, 0);
  }
  int t = 1;
  for(int i=q-1;i>=0;i--){
  	if(qs[i].ff == 2){
  		D.merge(e[qs[i].ss].ff, e[qs[i].ss].ss, t++);
  	}
  }
  for(int i=0;i<n;i++) sort(td(D.g[i]));
  for(int i=0;i<q;i++){
  	if(qs[i].ff == 1){
  		D.query(qs[i].ss);
  	}
  	else{
  		D.rollback(--t);
  	}
  }
}
int32_t main(){
  ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  int t=1;
  //cin >> t;
  while(t--){
    solve();
  }
}

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;

#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)

typedef long long ll;
typedef pair<int,int> pii;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> indexed_set;

const int maxN = 200005;
const int maxM = 300005;
const int maxQ = 500005;
const int INF = (int)2e9;

int N, M, Q, P[maxN], par[maxN], T[maxN];
pii E[maxM], Qs[maxQ];
bitset<maxM> f;
set<pii> sets[maxQ], elems[maxN];

void init(){
	for(int i=1; i<=N; ++i){
		elems[i].clear();
		elems[i].insert(mp(N-P[i], i));
		par[i] = -1;
	}
}

int find_root(int n){
	if(par[n]==-1) return n;
	return par[n]=find_root(par[n]);
}

bool unionAB(int a, int b, int i){
	a = find_root(a);
	b = find_root(b);
	if(a==b) return false;
	if(elems[a].size()>elems[b].size()) swap(a, b);
	if(i) sets[i] = elems[a];
	for(pii p : elems[a]) elems[b].insert(p);
	elems[a].clear();
	par[a] = b;
	return true;
}

bool unionAB(int a, int b){
	return unionAB(a, b, 0);
}

int main(){
	cin.sync_with_stdio(0);
	cin.tie(0);
	cin >> N >> M >> Q;
	for(int i=1; i<=N; ++i) cin >> P[i];
	for(int i=1; i<=M; ++i){
		int a, b; cin >> a >> b;
		E[i] = mp(a, b);
	}
	for(int i=1; i<=Q; ++i){
		int op, x;
		cin >> op >> x;
		Qs[i] = mp(op, x);
		if(op==2) f[x] = 1;
	}
	init();
	for(int i=1; i<=M; ++i){
		if(f[i]) continue;
		unionAB(E[i].first, E[i].second);
	}
	int x;
	for(int i=Q; i>0; --i){
		if(Qs[i].first==1) continue;
		x = Qs[i].second;
		unionAB(E[x].first, E[x].second, i);
	}
	init();
	vector<set<pii>> vec;
	for(int i=1; i<=M; ++i) unionAB(E[i].first, E[i].second);
	for(int i=1; i<=N; ++i){
		if(par[i]==-1){
			T[i] = (int)vec.size();
			vec.pb(elems[i]);
		}
	}
	for(int i=1; i<=N; ++i) T[i] = T[find_root(i)];
	for(int i=1; i<=Q; ++i){
		int op = Qs[i].first;
		x = Qs[i].second;
		if(op==1){
			if(vec[T[x]].empty()) printf("0\n");
			else{
				auto y = vec[T[x]].begin();
				pii p = mp(N, (*y).second);
				printf("%d\n", N-(*y).first);
				vec[T[x]].erase(y);
				vec[T[x]].insert(p);
			}
		}else{
			vec.pb(sets[i]);
			for(pii p : sets[i]){
				vec[T[p.second]].erase(p);
				T[p.second] = (int)vec.size()-1;
			}
		}
	}
	return 0;
}

#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef pair<int,int> P;
const int maxn=500003;
struct edge{int u,v;}e[maxn];
int n,m,Q,a[maxn],q[maxn][4],f[maxn],ee[maxn],sz[maxn];
bool vis[maxn];
set<int> g[maxn];
set<P> st[maxn];
int find(int x){while(f[x])x=f[x];return x;}
void dfs(int u,int last,int fu,int fv){
    st[fu].emplace(a[u],u),st[fv].erase(P(a[u],u));
    for(int v:g[u]){
        if(v==last)continue;
        dfs(v,u,fu,fv);
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&Q);
    for(int i=1;i<=n;i++)scanf("%d",a+i),sz[i]=1;
    for(int i=1;i<=m;i++)scanf("%d%d",&e[i].u,&e[i].v);
    int syk=0;
    for(int i=1;i<=Q;i++){
        scanf("%d%d",&q[i][0],&q[i][1]);
        if(q[i][0]==2)ee[++syk]=i,vis[q[i][1]]=1;
    }
    for(int i=1;i<=m;i++)if(!vis[i]){
        int fu=find(e[i].u),fv=find(e[i].v);
        if(fu!=fv){
            if(sz[fu]>sz[fv])swap(fu,fv);
            g[e[i].u].insert(e[i].v),g[e[i].v].insert(e[i].u);
            f[fu]=fv,sz[fv]+=sz[fu];
        }
    }
    for(int i=syk;i>=1;i--){
        int ii=q[ee[i]][1],fu=find(e[ii].u),fv=find(e[ii].v);
        if(fu!=fv){
            q[ee[i]][0]=3;
            if(sz[fu]>sz[fv])swap(fu,fv),swap(e[ii].u,e[ii].v);
            q[ee[i]][2]=fu,q[ee[i]][3]=fv;
            g[e[ii].u].insert(e[ii].v),g[e[ii].v].insert(e[ii].u);
            f[fu]=fv,sz[fv]+=sz[fu];
        }
    }
    for(int i=1;i<=n;i++)st[find(i)].emplace(a[i],i);
    for(int i=1;i<=Q;i++){
        if(q[i][0]==1){
            int tmp=find(q[i][1]);
            if(st[tmp].empty())puts("0");
            else{
                auto it=--st[tmp].end();
                printf("%d\n",it->fi);
                st[tmp].erase(it);
            }
        }
        if(q[i][0]==3){
            int u=e[q[i][1]].u,v=e[q[i][1]].v,fu=q[i][2],fv=q[i][3];
            f[fu]=0;
            g[u].erase(v),g[v].erase(u);
            dfs(u,v,fu,fv);
        }
// printf("i:%d ST:\n",i);for(int j=1;j<=n;j++){printf("rt:%d st:",j);for(auto l:st[j])printf(" %d",l.se);puts("");}
    }
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
int Read() {
	int x = 0, f = 1; char ch = getchar();
	while(!isdigit(ch)) {if(ch == '-')  f = -1; ch = getchar();}
	while(isdigit(ch)) {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar();}
	return x * f;
}
int first[600005], nxt[600005], to[600005], tot = 0;
void Add(int x, int y) {
	nxt[++tot] = first[x];
	first[x] = tot;
	to[tot] = y;
}
int ex[300005], ey[300005], vis[300005], rt[200005], tag[200005];
int sz[200005], bh[200005], a[200005], opt[200005], x[200005], vvis[200005], maxn[200005], minn[200005];
int L[200005], R[200005], rev[200005], mx[800005], Pos[800005];
void pushup(int o) {
	if(mx[o << 1] > mx[o << 1 | 1])  mx[o] = mx[o << 1], Pos[o] = Pos[o << 1];
	else  mx[o] = mx[o << 1 | 1], Pos[o] = Pos[o << 1 | 1];
}
void build(int o, int l, int r) {
	if(l == r) {mx[o] = a[rev[l]]; Pos[o] = l; return ;}
	int mid = (l + r) >> 1;
	build(o << 1, l, mid);
	build(o << 1 | 1, mid + 1, r);
	pushup(o);
}
void modify(int o, int l, int r, int pos, int val) {
	if(l == r) {mx[o] = val; return ;}
	int mid = (l + r) >> 1;
	if(pos <= mid)  modify(o << 1, l, mid, pos, val);
	else  modify(o << 1 | 1, mid + 1, r, pos, val);
	pushup(o);
}
pair<int, int> my_max(pair<int, int> A, pair<int, int> B) {
	return (A.first > B.first) ? A : B;
}
pair<int, int> query(int o, int l, int r, int nl, int nr) {
	if(nl <= l && r <= nr)  return make_pair(mx[o], Pos[o]);
	int mid = (l + r) >> 1; pair<int, int> ans;
	ans.first = ans.second = 0;
	if(nl <= mid)  ans = my_max(ans, query(o << 1, l, mid, nl, nr));
	if(mid < nr)  ans = my_max(ans, query(o << 1 | 1, mid + 1, r, nl, nr));
	return ans;
}
int findfa(int x) {return rt[x] == x ? x : rt[x] = findfa(rt[x]);}
void dfs(int u) {
	vvis[u] = 1;
	bh[u] += tag[u];
	for(int e = first[u]; e; e = nxt[e]) {
		int v = to[e];
		tag[v] += tag[u];
		dfs(v);
	}
}
signed main() {
	int n = Read(), m = Read(), q = Read();
	for(int i = 1; i <= n; i++)  sz[i] = bh[i] = 1, rt[i] = i, a[i] = Read();
	for(int i = 1; i <= m; i++)  ex[i] = Read(), ey[i] = Read();
	for(int i = 1; i <= q; i++) {
		opt[i] = Read(), x[i] = Read();
		if(opt[i] == 2)  vis[x[i]] = 1;
	}
	for(int i = 1; i <= m; i++) {
		if(!vis[i]) {
			int fx = findfa(ex[i]), fy = findfa(ey[i]);
			if(fx == fy)  continue;
			tag[fx] += sz[fy];
			sz[fy] += sz[fx]; rt[fx] = fy;
			Add(fy, fx);
		}
	}
	for(int i = q; i >= 1; i--) {
		if(opt[i] == 2) {
			int fx = findfa(ex[x[i]]), fy = findfa(ey[x[i]]);
			if(fx == fy)  continue;
			tag[fx] += sz[fy];
			sz[fy] += sz[fx]; rt[fx] = fy;
			Add(fy, fx);
		}
	}
	int sum = 0;
	for(int i = 1; i <= n; i++)
		if(!vvis[findfa(i)])  tag[rt[i]] += sum, sum += sz[rt[i]], dfs(rt[i]);
	for(int i = 1; i <= n; i++)
		maxn[i] = minn[i] = bh[i], rt[i] = i, rev[bh[i]] = i;
	for(int i = 1; i <= m; i++) {
		if(!vis[i]) {
			int fx = findfa(ex[i]), fy = findfa(ey[i]);
			if(fx == fy)  continue;
			maxn[fy] = max(maxn[fy], maxn[fx]);
			minn[fy] = min(minn[fy], minn[fx]);
			rt[fx] = fy;
		}
	}
	for(int i = q; i >= 1; i--) {
		if(opt[i] == 2) {
			int fx = findfa(ex[x[i]]), fy = findfa(ey[x[i]]);
			if(fx == fy)  continue;
			maxn[fy] = max(maxn[fy], maxn[fx]);
			minn[fy] = min(minn[fy], minn[fx]);
			rt[fx] = fy;
		}
		if(opt[i] == 1)
			L[i] = minn[findfa(x[i])], R[i] = maxn[findfa(x[i])];
	}
	build(1, 1, n);
	for(int i = 1; i <= q; i++) {
		if(opt[i] == 1) {
			pair<int, int> tmp = query(1, 1, n, L[i], R[i]);
			printf("%d\n", tmp.first);
			modify(1, 1, n, tmp.second, 0);
		}
	}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
template<class T> using oset=tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define sz(v) (int)v.size()
#define ar array
// #define f first
// #define s second
typedef vector<int> vi;
typedef long long ll;
typedef long double ld;
const int MAXN = 2e5+10, MAXM = 3e5+10, MAXQ = 5e5+10+MAXM, MAXL = 20, ALP = 26, MOD = 1e9+7, MAXK = 810;
const string  no = "NO\n", yes = "YES\n";
const int hA[4] = {1, 0, -1, 0}, kA[4] = {0, 1, 0, -1};
const ll INF = 9e18+10;

int n, m, q, a[MAXN], rp[MAXN], p[MAXN], sz[MAXN], split[MAXN], loc[MAXN], amt=0;
set<ar<int, 2>> ans[MAXN];
vector<int> ch[MAXN];
ar<int, 2> ed[MAXM], qs[MAXQ];
bool del[MAXN], used[MAXM];

int find_set(int v){
    return v==rp[v]?v:rp[v]=find_set(rp[v]);
}
int union_sets(int a, int b){
    // cout << a << ' ' << b << "\n";
    if ((a=find_set(a))==(b=find_set(b))) return -1;
    if (sz[a] < sz[b]) swap(a, b);
    p[b] = a, sz[a] += sz[b]; rp[b] = a; sz[b]=0;
    return b;
}
void er(set<ar<int, 2>>& s, ar<int, 2> c){
    s.erase(c);
}
void dfs(int c, int os, int ns){
    if (!del[c]) er(ans[os], ar<int, 2>{a[c], c}), ans[ns].insert(ar<int, 2>{a[c], c});
    loc[c] = ns;
    for (auto nxt : ch[c]) dfs(nxt, os, ns);
}

void fsc(int &x){
    register int c;
    x = 0; c=getchar();
    for(;(c>47 && c<58);c=getchar())
        x = (x<<1) + (x<<3) +c -48;
}
void solve(){
    fsc(n), fsc(m), fsc(q);
    for (int i = 0; i < n; i++) fsc(a[i]);
    for (int i = 0; i < m; i++) fsc(ed[i][0]), fsc(ed[i][1]), ed[i][0]--, ed[i][1]--;
    memset(used, 0, sizeof(used));
    for (int i = 0; i < q; i++){
        ar<int, 2> c; fsc(c[0]), fsc(c[1]), --c[1];
        qs[i]=c; if (c[0] == 2) used[c[1]]=1;
    }
    for (int i = 0; i < m; i++) if (!used[i]) qs[q] = ar<int, 2>{2, i}, q++;
    //each unite operation corresponds to a vertex
    //query -> query operation for a subtree
    //multiset -> small to large splitting?
    iota(p, p+n, 0); fill(sz, sz+n, 1); iota(rp, rp+n, 0); memset(split, -1, sizeof(split));
    for (int i = q-1; i >= 0; i--) if (qs[i][0] == 2) split[i] = union_sets(ed[qs[i][1]][0], ed[qs[i][1]][1]);//, cout << ed[qs[i][1]][0] << ' ' << ed[qs[i][1]][1] << ' ' << split[i] << '\n';
    for (int i = 0; i < n; i++) {
        if (p[i] != i) ch[p[i]].push_back(i);
        loc[i] = find_set(i); ans[loc[i]].insert({a[i], i});
    }
    for (int i = 0; i < q; i++){
        auto c = qs[i]; continue;
        if (c[0] == 1){
            auto& cur = ans[loc[c[1]]];
            if (cur.empty()){ cout << "0\n"; continue; }
            auto cans=*cur.rbegin(); del[cans[1]]=1;
            cout << cans[0] << '\n'; er(cur, cans);
        } else {
            int v = split[i];
            if (v == -1 || v==loc[v]) continue;
            dfs(v, loc[v], v);
        }
    }
}
int main(){
    ios::sync_with_stdio(false); cin.tie(nullptr);
    int t=1;
    // cin >> t;
    while (t--) solve();
}

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define mp make_pair
#define pb push_back
#define VI vector<int>
#define pii pair<int,int>
using namespace std;
const int MAXN = 5e5+10;
int u[MAXN], v[MAXN], per[MAXN];
int su[MAXN], sv[MAXN];
bool rmv[MAXN];
int p[MAXN];
int n, m, q;
int qi[MAXN], val[MAXN], sz[MAXN];
int find(int x){
	if(p[x] == x) return x;
	return p[x] = find(p[x]);
}
void join(int x, int y){
	sz[find(y)] += sz[find(x)];
	p[find(x)] = find(y);
}
bool out[MAXN];
set<int> S[MAXN];
int ss;
int where[MAXN];
vector<pii> g[MAXN];
bool V[MAXN];
int vis;
void dfs(int cur, int prev, int to){
	V[cur] = true;
	where[cur] = to;
	S[to].insert(cur);
	for(int i = 0; i < (int)g[cur].size(); i++){
		int next = g[cur][i].first;
		if(next == prev) continue;
		dfs(next, cur, to);
	}
}
void dfs1(int cur, int prev, int from, int to){
	vis++;
	S[from].erase(cur);
	if(!out[cur]) S[to].insert(cur);
	else S[to].insert(0);
	where[cur] = to;
	for(int i = 0; i < (int)g[cur].size(); i++){
		if(rmv[g[cur][i].second]) continue;
		int next = g[cur][i].first;
		if(next == prev) continue;
		dfs1(next, cur, from, to);
	}
}
int main(){
	scanf("%d %d %d", &n, &m, &q);
	for(int i = 1; i <= n; i++){
		scanf("%d", &per[i]);
		p[i] = i; sz[i] = 1;
	}
	for(int i = 1; i <= m; i++){
		scanf("%d %d", &u[i], &v[i]);
		u[i] = per[u[i]];
		v[i] = per[v[i]];
	}
	for(int i = 0; i < q; i++){
		scanf("%d %d", &qi[i], &val[i]);
		if(qi[i] == 2) rmv[val[i]] = true;
		else val[i] = per[val[i]];
	}
	for(int i = 1; i <= m; i++){
		if(rmv[i]) continue;
		if(find(u[i]) == find(v[i])) continue;
		join(u[i], v[i]);
	}
	for(int i = q-1; i >= 0; i--){
		if(qi[i] == 2){
			//ru[i] = find(u[val[i]]);
			//rv[i] = find(v[val[i]]);
			int x = u[val[i]], y = v[val[i]];
			if(find(x) == find(y)){
				su[i] = sv[i] = -1;
				continue;
			}
			su[i] = sz[find(x)];
			sv[i] = sz[find(y)];
			g[x].pb(mp(y,val[i]));
			g[y].pb(mp(x,val[i]));
			join(x, y);

		}
	}
	for(int i = 1; i <= n; i++){
		p[i] = i; sz[i] = 1;
	}
	for(int i = 1; i <= n; i++){
		for(int j = 0; j < (int)g[i].size(); j++){
			int x = i, y = g[i][j].first;
			join(x, y);
		}
	}
	for(int i = 1; i <= m; i++){
		int x = u[i], y = v[i];
		if(find(x) == find(y)) continue;
		g[x].pb(mp(y,i)); g[y].pb(mp(x,i));
		join(x, y);
	}
	ss = 0;
	memset(V, false, sizeof V);
	for(int i = 1; i <= n; i++){
		if(!V[i]) dfs(i, i, ss++);
	}
	for(int i = 1; i <= m; i++) rmv[i] = false;
	for(int i = 0; i < q; i++){
		if(qi[i] == 1){
			int cur = val[i];
			int w = where[cur];
			int ans = *S[w].rbegin();
			printf("%d\n", ans);
			if(ans){
				out[ans] = true;
				S[w].erase(ans);
				S[w].insert(0);
			}
		}else{
			rmv[val[i]] = true;
			if(su[i] == -1) continue;
			int ei = val[i];
			if(su[i] < sv[i]){
				vis = 0;
				dfs1(u[ei], u[ei], where[u[ei]], ss++);
				if(vis != su[i]){
					printf("%d %d\n", vis, su[i]);
					return 0;
				}
			}else{
				vis = 0;
				dfs1(v[ei], v[ei], where[v[ei]], ss++);
				if(vis != sv[i]){
					printf("%d %d\n", vis, sv[i]);
					return 0;
				}
			}
		}
	}
	return 0;
}

#include<bits/stdc++.h>

using namespace std;
const int MAXN = 500100;

int v[MAXN];
pair<int,int> grafo[MAXN] , q[MAXN];
bool are[MAXN];
int p[MAXN];

int pai[MAXN];
vector<int> vec[MAXN];

struct seg{
	seg *fe,*fd;
	int meio,l,r;
	pair<int,int> mex;

	seg(int x,int y){
		meio = (x + y) / 2;
		l = x , r = y;
		mex = {-1,0};

		if(l == r) return;

		fe = new seg(x,meio);
		fd = new seg(meio + 1,y);
	}

	void up(int pos,int novo){
		if(l == r){
			mex = {novo,l};
			return;
		}
		if(pos <= meio) fe->up(pos,novo);
		else fd->up(pos,novo);

		if(fe->mex.first >= fd->mex.first) mex = fe->mex;
		else mex = fd->mex;
	}

	pair<int,int> get(int a,int b){
		if(l >= a && r <= b) return mex;
		if(l > b || r < a) return {-1,0};

		pair<int,int> re = fe->get(a,b) , rd = fd->get(a,b);

		if(re.first >= rd.first) return re;
		return rd;
	}
};

int find(int x){
	if(pai[x] == x) return x;
	return pai[x] = find(pai[x]);
}

void join(int a,int b){
	a = find(a) , b = find(b);

	if(vec[a].size() >= vec[b].size()){
		for(int i = 0;i < vec[b].size();i++)
			vec[a].push_back(vec[b][i]);
		pai[b] = a;
	}
	else{
		for(int i = 0;i < vec[a].size();i++)
			vec[b].push_back(vec[a][i]);
		pai[a] = b;
	}
}

seg st(0,MAXN);

int main(){

	int n,m,Q;
	cin >> n >> m >> Q;

	for(int i = 1;i <= n;i++) cin >> v[i] , pai[i] = i , vec[i].push_back(i);

	for(int i = 1;i <= m;i++) cin >> grafo[i].first >> grafo[i].second;

	if(n > 100) return 0;

	for(int i = 1;i <= Q;i++){
		cin >> q[i].first >> q[i].second;
		if(q[i].first == 2) are[q[i].second] = true;
	}

	for(int i = 1;i <= m;i++){
		if(are[i] == true) continue;
		int a = grafo[i].first , b = grafo[i].second;
		if(find(a) == find(b)) continue;
		join(a,b);
	}

	vector<pair<int,int>> res;

	for(int i = Q;i >= 1;i--){
		if(q[i].first == 1){
			int a = find(q[i].second);
			res.push_back({a,vec[a].size()});
			//cout << "// " << a << " " << vec[a].size() << endl;
		}
		else{
			int a = find(grafo[q[i].second].first) , b = find(grafo[q[i].second].second);
			if(a == b) continue;
			join(a,b);
		}

		//for(int j = 1;j <= n;j++) cout << "|| " << j << " " << find(j) << endl;
		//cout << endl;
	}

	for(int i = 1;i < n;i++){
		if(find(i) == find(i + 1)) continue;
		join(i,i + 1);
	}

	if(n > 100) return 0;

	int h = find(1);
	for(int i = 0;i < n;i++) p[vec[h][i]] = i + 1 , st.up(i + 1,v[vec[h][i]]); //,cout << "/ " << i + 1 << " " << vec[h][i] << endl;

	for(int i = (int) res.size() - 1;i >= 0;i--){
		pair<int,int> h = st.get(p[res[i].first],p[res[i].first] + res[i].second - 1);
		cout << h.first << endl;
		st.up(h.second,0);
	}

}

#include <bits/stdc++.h>
using namespace std;
typedef long double ld;
typedef long long ll;
typedef pair<double, double> pdd;
typedef vector<double> vd;
typedef vector<vd> vvd;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef pair<int, int> pii;
typedef vector<pii> vii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<string> vs;
//const int mod = ;

vi p, sz, in, out;
vvi g;
int TIME = 0;

void dfs(int v) {
  ++TIME;
  in[v] = TIME;
  for (int nv : g[v]) {
    dfs(nv);
    sz[v] += sz[nv];
  }
  out[v] = TIME;
  //cerr << "dfs: " << v + 1 << ' ' << in[v] << ' ' << out[v] << endl;
}

int getp(int v) {
  if (p[v] == v) return v;
  return p[v] = getp(p[v]);
}

int join(int a, int b) {
  a = getp(a);
  b = getp(b);
  if (a == b) return -1;
  p[a] = b;
  g[b].push_back(a);
  return b;
}

const int N = 1 << 18;
pii ma[2 * N];

int main() {
  std::ios::sync_with_stdio(false); std::cin.tie(0);
  int n, m, Q;
  cin >> n >> m >> Q;
  vi a(n);
  p.resize(n);
  g.resize(n);
  sz.assign(n, 0);
  in.assign(n, 0);
  out.assign(n, 0);
  for (int i = 0; i < n; ++i) {
    cin >> a[i];
    p[i] = i;
  }
  vector<array<int, 2>> e(m);
  for (int i = 0; i < m; ++i) {
    cin >> e[i][0] >> e[i][1];
    --e[i][0];
    --e[i][1];
  }
  vi del(m);
  vector<array<int, 2>> q(Q);
  for (int i = 0; i < Q; ++i) {
    cin >> q[i][0] >> q[i][1];
    --q[i][1];
    if (q[i][0] == 2) del[q[i][1]] = 1;
  }
  for (int i = 0; i < m; ++i) if (!del[i]) join(e[i][0], e[i][1]);
  for (int i = Q - 1; i >= 0; --i) {
    if (q[i][0] == 1) {
      q[i][1] = getp(q[i][1]);
    } else {
      q[i][1] = join(e[q[i][1]][0], e[q[i][1]][1]);
    }
  }
  for (int i = 0; i < n; ++i) if (p[i] == i) dfs(i);
  for (int i = N; i < 2 * N; ++i) ma[i] = pii(-1, i - N);
  for (int i = 0; i < n; ++i) {
    ma[in[i] + N].first = a[i];
  }
  for (int i = N - 1; i > 0; --i) ma[i] = max(ma[2 * i], ma[2 * i + 1]);
  for (int t = 0; t < Q; ++t) {
    int v = q[t][1];
    if (q[t][0] == 1) {
      int l = in[v] + N, r = out[v] + N;
      pii best(0, in[v]);
      while (l <= r) {
        if (l & 1) {
          best = max(best, ma[l]);
          ++l;
        }
        if (!(r & 1)) {
          best = max(best, ma[r]);
          --r;
        }
        l /= 2;
        r /= 2;
      }
      int u = best.second;
      //cerr << v + 1 << ' ' << u + 1 << ' ';
      cout << best.first << '\n';
      int x = u + N;
      ma[x].first = 0;
      while (x > 1) {
        x /= 2;
        ma[x] = max(ma[2 * x], ma[2 * x + 1]);
      }
    } else if (v >= 0) {
      assert(!g[v].empty());
      out[v] -= sz[g[v].back()];
      g[v].pop_back();
    }
  }
  return 0;
}

#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
#include<tuple>
#include<cassert>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define Per(i,sta,n) for(int i=n-1;i>=sta;i--)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
const ld eps = 1e-8;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
template<class T>bool chmax(T &a, const T &b) {if(a<b){a=b;return 1;}return 0;}
template<class T>bool chmin(T &a, const T &b) {if(b<a){a=b;return 1;}return 0;}

template <class S, S (*op)(S, S), S (*e)()> struct SegmentTree {
  public:
    SegmentTree() : SegmentTree(0) {}
    SegmentTree(int n) : SegmentTree(std::vector<S>(n, e())) {}
    SegmentTree(const std::vector<S>& v) : _n(int(v.size())) {
        log = ceil_pow2(_n);
        size = 1 << log;
        d = std::vector<S>(2 * size, e());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set_val(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < _n);
        return d[p + size];
    }

    S query(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        S sml = e(), smr = e();
        l += size;
        r += size;

        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }

    S all_query() { return d[1]; }

    template <bool (*f)(S)> int max_right(int l) {//f(op([l,r)))==trueを満たす最大のr
        return max_right(l, [](S x) { return f(x); });
    }
    template <class F> int max_right(int l, F f) {
        assert(0 <= l && l <= _n);
        assert(f(e()));
        if (l == _n) return _n;
        l += size;
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < size) {
                    l = (2 * l);
                    if (f(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*f)(S)> int min_left(int r) {//f(op([l,r)))==trueを満たす最小のl
        return min_left(r, [](S x) { return f(x); });
    }
    template <class F> int min_left(int r, F f) {
        assert(0 <= r && r <= _n);
        assert(f(e()));
        if (r == 0) return 0;
        r += size;
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < size) {
                    r = (2 * r + 1);
                    if (f(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

  private:
    int _n, size, log;
    std::vector<S> d;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }

    int ceil_pow2(int n) {
        int x = 0;
        while ((1U << x) < (unsigned int)(n)) x++;
        return x;
    }
};

struct UnionFind {
private:
    vector<int> par,ran;
    vector<int> edge,size;
    int n;
public:
    UnionFind(int x){
      n=x;
      par.resize(n,0);
      ran.resize(n,0);
      edge.resize(n,0);
      size.resize(n,1);
      rep(i,n){
        par[i]=i;
      }
    }
    int find(int x) {
        if (par[x]==x)return x;
        else return par[x]=find(par[x]);
    }
    void unite(int x, int y) {
        x=find(x),y=find(y);
        if (x==y){
            edge[x]++;
            return;
        }
        if (ran[x]<ran[y]) {
            par[x]=y;
            size[y]+=size[x];
            edge[y]+=edge[x]+1;
        }
        else {
            par[y]=x;
            size[x]+=size[y];
            edge[x]+=edge[y]+1;
            if (ran[x]==ran[y])ran[x]++;
        }
    }
    bool same(int x,int y) {
        return find(x)==find(y);
    }
    int getSize(int x){
        return size[find(x)];
    }
    int getEdge(int x){
        return edge[find(x)];
    }
};

struct T{
  int idx,h;
  T(int h,int idx):h(h),idx(idx){}
  T(){}
};

T F(T a,T b){
  if(a.h>=b.h) return a;
  return b;
}

T e1(){return T(0,0);}

int n,m,q;
int a[200010];
P e[300010],qs[500010];
vector<int> G[600010];
vector<int> S[500010];
vector<bool> is_root;
P sec[600010];
int p[300010],inv[300010];

void dfs(int s,int &id){
  if(G[s].empty()) {
    id++;
    p[id]=s;
    inv[s]=id;
  }
  //cout << s << " " << id << endl;
  sec[s].first=id+1-(G[s].empty());
  for(int t:G[s]){
    dfs(t,id);
  }
  sec[s].second=id+1;
}

void solve(){
  scanf("%d%d%d",&n,&m,&q);
  rep(i,n) scanf("%d",&a[i]);
  rep(i,m){
    scanf("%d%d",&e[i].first,&e[i].second);
    e[i].first--;e[i].second--;
  }
  vector<P> units={};
  vector<bool> used(m,false);
  rep(i,q){
    scanf("%d%d",&qs[i].first,&qs[i].second);
    qs[i].second--;
    if(qs[i].first==2) {
      units.push_back(P(i,qs[i].second));
      used[qs[i].second]=true;
    }
  }
  rep(i,m){
    if(!used[i]) units.push_back(P(q,i));
  }
  int U=n;
  UnionFind uf(n);is_root.resize(n,true);
  vector<int> nodes(n);rep(i,n) nodes[i]=i;
  per(i,units.size()){
    P u=units[i];
    //cout << i << " " << e[u.second].first << " " << e[u.second].second << endl;
    if(uf.same(e[u.second].first,e[u.second].second)) continue;
    G[U].push_back(nodes[uf.find(e[u.second].first)]);
    G[U].push_back(nodes[uf.find(e[u.second].second)]);
    is_root[nodes[uf.find(e[u.second].first)]]=false;
    is_root[nodes[uf.find(e[u.second].second)]]=false;
    is_root.push_back(true);
    uf.unite(e[u.second].first,e[u.second].second);
    nodes[uf.find(e[u.second].first)]=U;
    S[u.first].push_back(U);
    U++;
  }
  int id=-1;
  set<P> se;
  rep(i,U){
    if(!is_root[i]) continue;
    dfs(i,id);
    se.insert(P(sec[i].first,sec[i].second));
  }
  vector<T> vec(n);
  rep(i,n) vec[i]=T(a[p[i]],i);
  SegmentTree<T,F,e1> seg(vec);
  //rep(i,U) cout << sec[i].first << " " << sec[i].second << endl;
  rep(i,q){
    for(int z:S[i]){
      int t1=G[z][0],t2=G[z][1];
      se.erase(sec[z]);
      se.insert(sec[t1]);
      se.insert(sec[t2]);
    }
    if(qs[i].first==1){
      //cout << inv[qs[i].second] << endl;
      auto it=se.lower_bound(P(inv[qs[i].second],mod));it--;
      P p=(*it);
      //cout << p.first << " " << p.second << endl;
      T t=seg.query(p.first,p.second);
      printf("%d\n",t.h);
      seg.set_val(t.idx,T(0,t.idx));
    }
  }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout << fixed << setprecision(50);
    solve();
}

#include <bits/stdc++.h>

using namespace std;
#define sim template < class c
#define ris return * this
#define dor > debug & operator <<
#define eni(x) sim > typename \
  enable_if<sizeof dud<c>(0) x 1, debug&>::type operator<<(c i) {
sim > struct rge { c b, e; };
sim > rge<c> range(c i, c j) { return rge<c>{i, j}; }
sim > auto dud(c* x) -> decltype(cerr << *x, 0);
sim > char dud(...);
struct debug {
#ifndef LOCAL
~debug() { cerr << endl; }
eni(!=) cerr << boolalpha << i; ris; }
eni(==) ris << range(begin(i), end(i)); }
sim, class b dor(pair < b, c > d) {
  ris << "(" << d.first << ", " << d.second << ")";
}
sim dor(rge<c> d) {
  *this << "[";
  for (auto it = d.b; it != d.e; ++it)
	*this << ", " + 2 * (it == d.b) << *it;
  ris << "]";
}
#else
sim dor(const c&) { ris; }
#endif
};
#define imie(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef pair<long long, int> pli;
typedef long long ll;
#define f first
#define s second
#define endl '\n'
#define all(x) x.begin(),x.end()
const int N=5e5+1;
int p[ N ],tin [ N ],tout[ N ],timer=0;
int get( int v ){
    return p[v] = ( v == p[v] ? v : get( p[ v ] ) );
}
int n,m,q;
vector<int> g [ N ];
pii t[ 4 * N ];
int a[ N ];
int obr[N];
void mg(int a, int b){
    int c = get( a ), d = get( b );
    if(c == d) return;
    n++;
    p[c]=n;
    p[d]=n;
    g[ n ].emplace_back(c);
    g[ n ].emplace_back(d);
    return ;
}
void dfs(int v, int p){
    tin[ v ] = ++timer;
    obr[ timer ] = v;
    for(auto &z : g[ v ]){
        dfs( z, v );
    }
    tout[ v ] = timer;
}
void b_tr(int v,int tl,int tr){
    if(tl == tr){
        t[v]={a[obr[tl]],tl};
    }
    else{
        int tm=(tl+tr)>>1;
        b_tr(2*v,tl,tm);
        b_tr(2*v+1,tm+1,tr);
        t[v]=max(t[2*v],t[2*v+1]);
    }
}
pii getMax(int l,int r,int v,int tl,int tr){
    if(tl>=l && tr<=r){
        return t[v];
    }
    if(tl>r || tr<l) return {0,n};
    int tm=(tl+tr)>>1;
    return max(getMax(l,r,2*v,tl,tm),getMax(l,r,2*v+1,tm+1,tr));
}
void upd(int id,int v,int tl,int tr){
    if(tl==tr){
        t[v].first=0;
        return ;
    }
    int tm=(tl+tr)>>1;
    if(tm>=id)
        upd(id,2*v,tl,tm);
    else
        upd(id,2*v+1,tm+1,tr);
    t[v]=max(t[2*v],t[2*v+1]);
}
pii e[N];
bool ex[N];
pii qe[N];
signed main(){
    cin.tie(0);cout.tie(0);ios_base::sync_with_stdio(false);
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i = 0;i < m;i++){
        int v,u;
        cin>>v>>u;
        e[i]={v,u};
    }
    iota(p,p+N,0);
    for(int i = 0;i < q;i++){
        int tp;
        cin>>tp;
        int id;
        cin>>id;
        if(tp==2){
            ex[id-1]=1;
        }
        qe[i]={tp,id};
    }
    for(int i = 0; i < m;i++){
        if(!ex[i]){
            mg(e[i].f,e[i].s);
        }
    }
    for(int i = q - 1; ~ i; --i){
        if(qe[i].f==2)
            mg(e[qe[i].s-1].f,e[qe[i].s-1].s);
        else {
            qe[i].s=get(qe[i].s);
        }
    }
    for(int i = 1;i <= n; i++){
        if(get(i)==i)
            dfs(i,i);
    }
    b_tr(1,1,N-1);
    for(int i = 0; i<q; i++){
        if(qe[i].f==1){
            int id=qe[i].s;
            auto w=getMax(tin[id],tout[id],1,1,N-1);
            upd(w.s,1,1,N-1);
            cout<<w.f<<endl;
        }
    }
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
pair<int,int> st[800005],tv[500005],c[500005];
int f[200005],f2[200005],n,m,q,nx[200005],l[200005],r[200005],cnt,cnt2,u,v,x[200005],p[200005],cs[200005],deg[200005],vt[200005],L,R;
vector<int> vec[200005];
bool kt[300005];
set<int> s;
set<int> :: iterator it;
void up(int id,int l,int r,int vt,int gt)
{
    if (l>r || l>vt || r<vt) return;
    if (l==r)
    {
        st[id]={gt,vt};
        return;
    }
    int mid=(l+r)/2;
    up(id*2,l,mid,vt,gt);
    up(id*2+1,mid+1,r,vt,gt);
    st[id]=max(st[id*2],st[id*2+1]);
}
pair<int,int> get(int id,int l,int r,int u,int v)
{
    if (l>r || l>v || r<u) return {0,0};
    if (l>=u && r<=v) return st[id];
    int mid=(l+r)/2;
    return max(get(id*2,l,mid,u,v),get(id*2+1,mid+1,r,u,v));

}
int phin(int u)
{
    return f[u]<0 ? u : f[u]=phin(f[u]);
}
void uni(int u,int v)
{
    if (f[u]>f[v]) swap(u,v);
    f[u]+=f[v];
    f[v]=u;
}
int phin2(int u)
{
    return f2[u]<0 ? u : f2[u]=phin(f2[u]);
}
void uni2(int u,int v,int i)
{
    if (f2[u]>f2[v]) swap(u,v);
    nx[r[u]]=l[v];
    deg[l[v]]++;
    x[r[u]]=i;
    r[u]=r[v];
    f2[u]+=f2[v];
    f2[v]=u;
}
int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>m>>q;bool db=false;
    if (n==96 && m==141 & q==151) db=true;
    for (int i=1;i<=n;++i) cin>>p[i];
    memset(f,-1,sizeof(f));
    for (int i=1;i<=m;++i) cin>>c[i].first>>c[i].second;
    for (int i=1;i<=q;++i)
     {
         cin>>tv[i].first>>tv[i].second;
         if (tv[i].first==2) kt[tv[i].second]=true;
     }
    for (int i=1;i<=m;++i)
     if (!kt[i])
    {
        u=c[i].first;
        v=c[i].second;
        u=phin(u);
        v=phin(v);
        if (u!=v) uni(u,v);
    }
    for (int i=1;i<=n;++i)
     if (i==phin(i)) {++cnt;l[cnt]=r[cnt]=cnt;cs[i]=cnt;}
    for (int i=1;i<=n;++i)
     vec[cs[phin(i)]].push_back(i);
    memset(f2,-1,sizeof(f2));
    for (int i=q;i>0;--i)
     if (tv[i].first==2)
    {
        u=c[tv[i].second].first;
        v=c[tv[i].second].second;
        u=cs[phin(u)];
        v=cs[phin(v)];
        u=phin2(u);
        v=phin2(v);
        if (u!=v) uni2(u,v,i);
    }
    memset(cs,0,sizeof(cs));
    s.insert(0);

    for (int i=1;i<=cnt;++i)
     if (deg[i]==0)
    {
        u=i;
        while (1)
        {
            for (int j=0;j<vec[u].size();++j) {++cnt2;up(1,1,n,cnt2,p[vec[u][j]]);vt[vec[u][j]]=cnt2;}
            if (nx[u])
             {
                 cs[x[u]]=cnt2;
                 u=nx[u];
             }
             else break;
            if (cnt2>n) cout<<u<<endl;
            if (cnt2-n==n) return 0;
        }
        s.insert(cnt2);

    }

    for (int i=1;i<=q;++i)
    {
        if (tv[i].first==1)
        {
           it=s.lower_bound(vt[tv[i].second]);
           R=(*it);
           it--;
           L=(*it)+1;
           pair<int,int> X=get(1,1,n,L,R);
           cout<<X.first<<'\n';
           up(1,1,n,X.second,0);
        }
        else s.insert(cs[i]);
    }

    return 0;
}

/*
 * Package: StandardCodeLibrary.Core
 * */
//引进常用的头文件并使用std名字空间;
#include <algorithm>
#include <bitset>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
using namespace std;

//用于减少代码量的宏;
#define lp for (;;)
#define repf(i, a, b) for (int i = (a); i < (b); ++i)
#define ft(i, a, b) for (int i = (a); i <= (b); ++i)
#define fdt(i, a, b) for (int i = (a); i >= (b); --i)
#define rrepf(i, a, b) fdt(i, (a)-1, b)
#define rep(i, n) repf(i, 0, n)
#define rrep(i, n) rrepf(i, n, 0)
#define for_each(e, s)                                                         \
  for (__typeof__((s).begin()) e = (s).begin(); e != (s).end(); ++e)
#define for_nonempty_subsets(subset, set)                                      \
  for (int subset = set; subset; subset = (subset - 1) & (set))
#define for_in_charset(i, charset) for (cstr i = (charset); *i; i++)
#define whl(x) while (x)
#define rtn return
#define fl(x, y) memset((x), char(y), sizeof(x))
#define clr(x) fl(x, char(0))
#define cpy(x, y) memcpy(x, y, sizeof(x))
#define sf scanf
#define pf printf
#define vec vector
#define pr pair
#define que queue
#define prq priority_queue
#define itr iterator
#define x first
#define y second
#define pb push_back
#define mp make_pair
#define ins insert
#define ers erase
#define lb lower_bound
#define ub upper_bound
#define rnk order_of_key
#define sel find_by_order
#define ctz __builtin_ctz
#define clz __builtin_clz
#define bc __builtin_popcount
#define sz(x) (int((x).size()))
#define all(x) (x).begin(), (x).end()
#define srt(x) sort(all(x))
#define uniq(x) srt(x), (x).erase(unique(all(x)), (x).end())
#define rev(x) reverse(all(x))
#define shf(x) random_shuffle(all(x))
#define nxtp(x) next_permutation(all(x))

//调试相关的宏;
#ifndef DEBUG
#define prt(x) (cerr)
#define asrtWA(s)                                                              \
  do                                                                           \
    if (!(s))                                                                  \
      exit(0);                                                                 \
  whl(0)
#define asrtTLE(s)                                                             \
  do                                                                           \
    if (!(s))                                                                  \
      whl(1);                                                                  \
  whl(0)
#define asrtMLE(s)                                                             \
  do                                                                           \
    if (!(s))                                                                  \
      whl(new int);                                                            \
  whl(0)
#define asrtOLE(s)                                                             \
  do                                                                           \
    if (!(s))                                                                  \
      whl(1) puts("OLE");                                                      \
  whl(0)
#define asrtRE(s)                                                              \
  do                                                                           \
    if (!(s))                                                                  \
      *(int *)0 = 0;                                                           \
  whl(0)
#define runtime() (cerr)
#define input(in) freopen(in, "r", stdin)
#define output(out) freopen(out, "w", stdout)
#else
#define prt(x) cerr << "第" << __LINE__ << "行\t: " << #x "\t=" << (x) << endl
#define asrtWA(s)                                                              \
  do                                                                           \
    if (!(s))                                                                  \
      cerr << "assert(" #s ")" << endl;                                        \
  whl(0)
#define asrtTLE(s)                                                             \
  do                                                                           \
    if (!(s))                                                                  \
      cerr << "assert(" #s ")" << endl;                                        \
  whl(0)
#define asrtMLE(s)                                                             \
  do                                                                           \
    if (!(s))                                                                  \
      cerr << "assert(" #s ")" << endl;                                        \
  whl(0)
#define asrtOLE(s)                                                             \
  do                                                                           \
    if (!(s))                                                                  \
      cerr << "assert(" #s ")" << endl;                                        \
  whl(0)
#define asrtRE(s)                                                              \
  do                                                                           \
    if (!(s))                                                                  \
      cerr << "assert(" #s ")" << endl;                                        \
  whl(0)
#define runtime()                                                              \
  cerr << "Used: " << db(clock()) / CLOCKS_PER_SEC << "s" << endl
#define input(in)
#define output(out)
#endif

//常用数据类型;
typedef long long int lli;
typedef double db;
typedef const char *cstr;
typedef string str;
typedef vec<int> vi;
typedef vec<vi> vvi;
typedef vec<lli> vl;
typedef vec<vl> vvl;
typedef vec<bool> vb;
typedef vec<vb> vvb;
typedef vec<char> vc;
typedef vec<vc> vvc;
typedef vec<str> vs;
typedef pr<int, int> pii;
typedef pr<lli, lli> pll;
typedef pr<db, db> pdd;
typedef vec<pii> vpii;
typedef vec<pll> vpll;
typedef vec<pdd> vpdd;
typedef map<int, int> mii;
typedef map<str, int> msi;
typedef map<char, int> mci;
typedef set<int> si;
typedef set<str> ss;
typedef que<int> qi;

//常用常量:int的最大值;lli的最大值;db的误差相关常数;欧拉常数;圆周率;移动向量;取模使用的除数;
int oo = (~0u) >> 1;
lli ooll = (~0ull) >> 1;
db inf = 1e+10;
db eps = 1e-10;
db gam = 0.5772156649015328606;
db pi = acos(-1.0);
int dx[] = {1, 0, -1, 0, 1, -1, -1, 1, 0};
int dy[] = {0, 1, 0, -1, 1, 1, -1, -1, 0};
int MOD = 1000000007;

//常用函数:最大最小值更新;数学相关函数;输入和输出;树状数组;并查集;可合并堆;
template <typename type> inline bool cmax(type &a, const type &b) {
  rtn a < b ? a = b, true : false;
}
template <typename type> inline bool cmin(type &a, const type &b) {
  rtn b < a ? a = b, true : false;
}
template <typename type> inline type sqr(const type &x) { rtn x *x; }
template <typename type> inline type mod(const type &x) { rtn x % MOD; }
inline int sgn(const db &x) { rtn(x > +eps) - (x < -eps); }
inline int dbcmp(const db &a, const db &b) { rtn sgn(a - b); }
template <typename type>
inline pr<type, type> operator-(const pr<type, type> &x) {
  rtn mp(-x.x, -x.y);
}
template <typename type>
inline pr<type, type> operator+(const pr<type, type> &a,
                                const pr<type, type> &b) {
  rtn mp(a.x + b.x, a.y + b.y);
}
template <typename type>
inline pr<type, type> operator-(const pr<type, type> &a,
                                const pr<type, type> &b) {
  rtn mp(a.x - b.x, a.y - b.y);
}
template <typename type>
inline pr<type, type> operator*(const pr<type, type> &a, const type &b) {
  rtn mp(a.x * b, a.y * b);
}
template <typename type>
inline pr<type, type> operator/(const pr<type, type> &a, const type &b) {
  rtn mp(a.x / b, a.y / b);
}
template <typename type>
inline pr<type, type> &operator-=(pr<type, type> &a, const pr<type, type> &b) {
  rtn a = a - b;
}
template <typename type>
inline pr<type, type> &operator+=(pr<type, type> &a, const pr<type, type> &b) {
  rtn a = a + b;
}
template <typename type>
inline pr<type, type> &operator*=(pr<type, type> &a, const type &b) {
  rtn a = a * b;
}
template <typename type>
inline pr<type, type> &operator/=(pr<type, type> &a, const type &b) {
  rtn a = a / b;
}
template <typename type>
inline type cross(const pr<type, type> &a, const pr<type, type> &b) {
  rtn a.x *b.y - a.y *b.x;
}
template <typename type>
inline type dot(const pr<type, type> &a, const pr<type, type> &b) {
  rtn a.x *b.x + a.y *b.y;
}
template <typename type> inline type gcd(type a, type b) {
  if (b)
    whl((a %= b) && (b %= a));
  rtn a + b;
}
template <typename type> inline type lcm(type a, type b) {
  rtn a *b / gcd(a, b);
}
inline lli bin_pow(lli x, lli y) {
  lli z = 1;
  whl(y) {
    if (y & 1)
      z = mod(z * x);
    x = mod(sqr(x)), y >>= 1;
  }
  rtn z;
}
template <typename istream, typename first_type, typename second_type>
inline istream &operator>>(istream &cin, pr<first_type, second_type> &x) {
  rtn cin >> x.x >> x.y;
}
template <typename ostream, typename first_type, typename second_type>
inline ostream &operator<<(ostream &cout,
                           const pr<first_type, second_type> &x) {
  rtn cout << x.x << " " << x.y;
}
template <typename istream, typename type>
inline istream &operator>>(istream &cin, vec<type> &x) {
  rep(i, sz(x)) cin >> x[i];
  rtn cin;
}
template <typename ostream, typename type>
inline ostream &operator<<(ostream &cout, const vec<type> &x) {
  rep(i, sz(x)) cout << x[i] << (i + 1 == sz(x) ? "" : " ");
  rtn cout;
}
inline ostream &pdb(int prcs, db x) {
  rtn cout << setprecision(prcs) << fixed << (sgn(x) ? (x) : 0);
}
template <typename type> inline void bit_inc(vec<type> &st, int x, type inc) {
  whl(x < sz(st)) st[x] += inc, x |= x + 1;
}
template <typename type> inline type bit_sum(const vec<type> &st, int x) {
  type s = 0;
  whl(x >= 0) s += st[x], x = (x & (x + 1)) - 1;
  rtn s;
}
template <typename type> inline type bit_kth(const vec<type> &st, int k) {
  int x = 0, y = 0, z = 0;
  whl((1 << (++y)) <= sz(st));
  rrep(i, y) {
    if ((x += 1 << i) > sz(st) || z + st[x - 1] > k)
      x -= 1 << i;
    else
      z += st[x - 1];
  }
  rtn x;
}
inline void make_set(vi &st) { rep(i, sz(st)) st[i] = i; }
inline int find_set(vi &st, int x) {
  int y = x, z;
  whl(y != st[y]) y = st[y];
  whl(x != st[x]) z = st[x], st[x] = y, x = z;
  rtn y;
}
inline bool union_set(vi &st, int a, int b) {
  a = find_set(st, a), b = find_set(st, b);
  rtn a != b ? st[a] = b, true : false;
}
inline void make_set(vpii &st) { rep(i, sz(st)) st[i] = mp(i, 1); }
inline int find_set(vpii &st, int x) {
  int y = x, z;
  whl(y != st[y].x) y = st[y].x;
  whl(x != st[x].x) z = st[x].x, st[x].x = y, x = z;
  rtn y;
}
inline bool union_set(vpii &st, int a, int b) {
  a = find_set(st, a), b = find_set(st, b);
  rtn a != b ? (st[a].y > st[b].y ? st[a].x = b,
                st[a].y += st[b].y : st[b].x = a, st[b].y += st[a].y),
      true : false;
}
template <typename type> inline void merge(type &a, type &b) {
  if (sz(a) < sz(b))
    swap(a, b);
  whl(sz(b)) a.ins(*b.begin()), b.ers(b.begin());
}

//初始化;
struct Initializer {
#ifndef DEBUG
  Initializer() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
  }
#else
  ~Initializer() { runtime(); }
#endif
} initializer;

//非标准;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tag_and_trait.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>
typedef __gnu_cxx::rope<char> rope;
template <typename key, typename value>
class ext_map
    : public __gnu_pbds::tree<key, value, less<key>, __gnu_pbds::rb_tree_tag,
                              __gnu_pbds::tree_order_statistics_node_update> {};
template <typename key>
class ext_set
    : public __gnu_pbds::tree<key, __gnu_pbds::null_type, less<key>,
                              __gnu_pbds::rb_tree_tag,
                              __gnu_pbds::tree_order_statistics_node_update> {};

struct node {
  int sz;
  int p;
  int val;
  pii max;
  set<pii> q;
};

int main() {
  int n, m, q;
  cin >> n >> m >> q;
  vi p(n);
  cin >> p;
  vpii e(m);
  cin >> e;
  rep(i, m) {
    e[i].x--;
    e[i].y--;
  }
  vi pos(m, q);
  vpii qry;
  rep(i, q) {
    int t, x;
    cin >> t >> x;
    if (t == 1) {
      qry.pb(mp(i, x - 1));
    } else {
      pos[x - 1] = i;
    }
  }
  vi rpos(m);
  rep(i, m) rpos[i] = i;
  sort(all(rpos), [&](int x, int y) { return pos[x] < pos[y]; });
  vec<node> nodes(n);
  rep(i, n) {
    nodes[i].sz = 1;
    nodes[i].p = -1;
    nodes[i].val = p[i];
    nodes[i].max = mp(p[i], i);
  }
  auto find = [&](int x) {
    while (nodes[x].p != -1) {
      x = nodes[x].p;
    }
    return x;
  };
  auto update = [&](int x, bool ers = false, pii e = mp(0, 0)) {
    lp {
      pii old = nodes[x].max;
      pii nw = mp(nodes[x].val, x);
      if (ers) {
        nodes[x].q.ers(e);
      }
      if (sz(nodes[x].q))
        cmax(nw, *nodes[x].q.rbegin());
      // prt(nw);
      // prt(old);
      // prt(x);
      nodes[x].max = nw;
      x = nodes[x].p;
      if (x == -1) {
        break;
      }
      nodes[x].q.ers(old);
      nodes[x].q.ins(nw);
    }
  };
  auto merge = [&](int x, int y) {
    x = find(x), y = find(y);
    if (x == y) {
      return -1;
    }
    if (nodes[x].sz < nodes[y].sz) {
      swap(x, y);
    }
    // prt(mp(x, y));
    nodes[x].p = y;
    nodes[y].sz += nodes[x].sz;
    nodes[y].q.ins(nodes[x].max);
    // prt(nodes[x].max);
    // prt(nodes[y].max);
    // prt(*nodes[y].q.rbegin());
    // prt(y);
    update(y);
    // prt(nodes[x].max);
    // prt(nodes[y].max);
    return x;
  };
  auto unlink = [&](int x) {
    if (x == -1)
      return;
    int y = nodes[x].p;
    nodes[x].p = -1;
    nodes[y].q.erase(nodes[x].max);
    update(y, true, nodes[x].max);
  };
  auto sol = [&](int x) {
    x = find(x);
    int ret = nodes[x].max.x;
    int u = nodes[x].max.y;
    nodes[u].val = 0;
    update(u, true, nodes[x].max);
    return ret;
  };
  vi rt(m);
  rrep(i, m) {
    pii w = e[rpos[i]];
    rt[rpos[i]] = merge(w.x, w.y);
  }
  int j = 0;
  prt(nodes[find(0)].max);
  rep(i, sz(qry)) {
    while (j < m && pos[rpos[j]] < qry[i].x) {
      j++;
      unlink(rt[rpos[j]]);
    }
    prt(i);
    cout << sol(qry[i].y) << endl;
  }
}

#include <bits/stdc++.h>

using namespace std;

template <typename T>
void debug_out(T t) {
  cerr << t;
}

template <typename A, typename B>
void debug_out(pair<A, B> u) {
  cerr << "(" << u.first << " " << u.second << ")";
}

template <typename T>
void debug_out(vector<T> t) {
  int sz = t.size();
  for(int i = 0; i < sz; i++) {
    debug_out(t[i]);
    if(i != sz - 1) cerr << ", ";
  }
}

template <typename T>
void debug_out(vector<vector<T>> t) {
  int sz = t.size();
  for(int i = 0; i < sz; i++) {
    debug_out(t[i]);
    if(i != sz - 1) cerr << endl;
  }
}

template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
  debug_out(H);
  cerr << " ";
  debug_out(T...);
}

template <typename T>
void debug_out(set<T> a) {
  vector<T> _a;
  for(T t : a) _a.push_back(t);
  debug_out(_a);
}

#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:" << endl, debug_out(__VA_ARGS__), cerr << endl;

class dsu {
 public:
  vector<int> p;
  int n;
  vector<vector<int>> d;

  dsu(int _n) : n(_n) {
    p.resize(n);
    iota(p.begin(), p.end(), 0);
    for(int i = 0; i < n; i++) d.push_back({i});
  }

  inline int get(int x) {
    return p[x];
  }

  inline bool unite(int x, int y) {
    x = get(x);
    y = get(y);
    if(x == y) return false;
    if(d[x].size() < d[y].size()) swap(x, y);
    for(int i : d[y]) {
      p[i] = x;
      d[x].push_back(i);
    }
    return true;
  }
};

int n, m, q;

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  cin >> n >> m >> q;
  vector<int> p(n);
  for(int i = 0; i < n; i++) cin >> p[i];
  vector<pair<int, int>> edges;
  for(int i = 0; i < m; i++) {
    int a, b;
    cin >> a >> b;
    a--; b--;
    edges.emplace_back(a, b);
  }
  vector<pair<int, int>> que(q);
  vector<int> alive(m, 1);
  for(int i = 0; i < q; i++) {
    int a, b;
    cin >> a >> b;
    b--;
    que[i] = make_pair(a, b);
    if(a == 2) alive[b] = 0;
  }
  dsu d(n);
  for(int i = 0; i < m; i++) if(alive[i]) {
    int a = edges[i].first;
    int b = edges[i].second;
    d.unite(a, b);
  }
  vector<vector<int>> rev(q);
  for(int i = q - 1; i >= 0; i--) {
    int a = que[i].first;
    int b = que[i].second;
    if(a == 2) {
      int u = edges[b].first;
      int v = edges[b].second;
      u = d.get(u);
      v = d.get(v);
      if(u == v) continue;
      rev[i] = d.d[u].size() > d.d[v].size() ? d.d[v] : d.d[u];
      d.unite(u, v);
    }
  }
  d = dsu(n);
  for(int i = 0; i < m; i++) {
    int a = edges[i].first;
    int b = edges[i].second;
    d.unite(a, b);
  }
  vector<set<int>> ret(n);
  vector<int> to(n);
  for(int i = 0; i < n; i++) to[i] = d.get(i);
  for(int i = 0; i < n; i++) ret[to[i]].insert(p[i]);
  vector<int> unused;
  for(int i = 0; i < n; i++) if(ret[i].empty()) unused.push_back(i);
  vector<int> dead(n);
  for(int qs = 0; qs < q; qs++) {
    int x = que[qs].first;
    int y = que[qs].second;
    if(x == 1) {
      y = to[y];
      if(ret[y].empty()) {
        cout << "0\n";
        continue;
      }
      int p = *prev(ret[y].end());
      dead[p - 1] = 1;
      cout << *prev(ret[y].end()) << "\n";
      ret[y].erase(prev(ret[y].end()));
    } else {
      int a = edges[y].first;
      int b = edges[y].second;
      if(rev[y].empty()) continue;
      int id = unused.back();
      unused.pop_back();
      a = to[a];
      for(int i : rev[y]) {
         to[i] = id;
        if(dead[p[i] - 1]) continue;
        ret[a].erase(p[i]);
        ret[id].insert(p[i]);
      }
    }
  }
  return 0;
}

#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
int n,m,Q;
int fa[600005],u[300005],v[300005];
int getfa(int x){
	if(x!=fa[x])fa[x]=getfa(fa[x]);
	return fa[x];
}
void Merge(int x,int y){
	fa[x]=y;
}
struct Query{
	int type,pos;
}q[500005];
bool usd[300005];
int value[600005],num,valuepos[600005];
struct edge{
	int from,to,nxt;
}e[2000005],ee[600005];
int Head[600005],cnt,cntt,Headd[600005],root[600005],lg[600005];
int depth[600005],f[600005][25];
void add(int x,int y){
	++cnt;
	e[cnt].from=x;
	e[cnt].to=y;
	e[cnt].nxt=Head[x];
	Head[x]=cnt;
}
void addd(int x,int y){
	++cntt;
	ee[cntt].from=x;
	ee[cntt].to=y;
	ee[cntt].nxt=Headd[x];
	Headd[x]=cntt;
}
bool vis[500005];
void dfs(int now,int pre){
	fa[now]=num;
	vis[now]=true;
	add(now,num);
	add(num,now);
	for(int i=Headd[now];i;i=ee[i].nxt){
		int to=ee[i].to;
		if(to==pre||vis[to])continue;
		dfs(to,now);
	}
}
int dfn[500005],sz[500005],tmpcnt,seq[500005];
void dfss(int now,int pre){
	f[now][0]=pre;
	dfn[now]=++tmpcnt;
	seq[tmpcnt]=now;
	sz[now]=1;
	for(int i=1;(1<<i)<=depth[now];++i)f[now][i]=f[f[now][i-1]][i-1];
	for(int i=Head[now];i;i=e[i].nxt){
		if(e[i].to==pre)continue;
		depth[e[i].to]=depth[now]+1;
		dfss(e[i].to,now);
		sz[now]+=sz[e[i].to];
	}
}
int Max[600005<<2];
void build(int l,int r,int rt){
	if(l==r){
		Max[rt]=value[seq[l]];
		return;
	}
	int m=(l+r)>>1;
	build(lson);
	build(rson);
	Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}
void modify(int l,int r,int rt,int pos){
	if(l==r){
		Max[rt]=0;
		return;
	}
	int m=(l+r)>>1;
	if(pos<=m)modify(lson,pos);
	else modify(rson,pos);
	Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}
int query(int l,int r,int rt,int nowl,int nowr){
	if(nowl<=l&&r<=nowr)return Max[rt];
	int m=(l+r)>>1,re=0;
	if(m>=nowl)re=max(re,query(lson,nowl,nowr));
	if(m<nowr)re=max(re,query(rson,nowl,nowr));
	return re;
}
void init(){
	for(int i=1;i<=3*n;++i)lg[i]=lg[i-1]+(1<<lg[i-1]==i);
}
int lca(int x,int y){
	if(depth[x]<depth[y])swap(x,y);
	while(depth[x]>depth[y])x=f[x][lg[depth[x]-depth[y]]-1];
	if(x==y)return x;
	for(int k=lg[depth[x]]-1;k>=0;--k){
		if(f[x][k]!=f[y][k]){
			x=f[x][k];
			y=f[y][k];
		}
	}
	return f[x][0];
}
int main(){
	scanf("%d%d%d",&n,&m,&Q);
	init();
	for(int i=1;i<=3*n;++i)fa[i]=i;
	for(int i=1;i<=n;++i)scanf("%d",&value[i]),valuepos[value[i]]=i;
	for(int i=1;i<=m;++i)scanf("%d%d",&u[i],&v[i]);
	for(int i=1;i<=Q;++i){
		scanf("%d%d",&q[i].type,&q[i].pos);
		if(q[i].type==2)usd[q[i].pos]=true;
	}
	num=n;
	for(int i=1;i<=m;++i){
		if(!usd[i]){
			addd(u[i],v[i]);
			addd(v[i],u[i]);
		}
	}
	for(int i=1;i<=n;++i){
		if(!vis[i]){
			++num;
			dfs(i,0);
		}
	}
	for(int i=Q;i>=1;--i){
		if(q[i].type==2){
			int r1=getfa(u[q[i].pos]),r2=getfa(v[q[i].pos]);
			if(r1!=r2){
				++num;
				fa[r1]=fa[r2]=num;
				add(r1,num);
				add(r2,num);
				add(num,r1);
				add(num,r2);
			}
		}
		else root[i]=getfa(q[i].pos);
	}
	++num;
	for(int i=1;i<num;++i){
		fa[i]=getfa(i);
		if(fa[i]==i){
			fa[i]=num;
			add(i,num);
			add(num,i);
		}
	}
	dfss(num,0);
	build(1,num,1);
	for(int i=1;i<=Q;++i){
		if(q[i].type==1){
			int ans=query(1,num,1,dfn[root[i]],dfn[root[i]]+sz[root[i]]-1);
			printf("%d\n",ans);
			if(ans)modify(1,num,1,dfn[valuepos[ans]]);
		}
	}
	return 0;
}

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define mp make_pair
#define pb push_back
#define VI vector<int>
#define pii pair<int,int>
using namespace std;
const int MAXN = 5e5+10;
int u[MAXN], v[MAXN], per[MAXN];
int su[MAXN], sv[MAXN];
bool rmv[MAXN];
int p[MAXN];
int n, m, q;
int qi[MAXN], val[MAXN], sz[MAXN];
int find(int x){
	if(p[x] == x) return x;
	return p[x] = find(p[x]);
}
void join(int x, int y){
	sz[find(y)] += sz[find(x)];
	p[find(x)] = find(y);
}
bool out[MAXN];
set<int> S[MAXN];
int ss;
int where[MAXN];
vector<pii> g[MAXN];
bool V[MAXN];
void dfs(int cur, int prev, int to){
	V[cur] = true;
	where[cur] = to;
	S[to].insert(cur);
	for(int i = 0; i < (int)g[cur].size(); i++){
		int next = g[cur][i].first;
		if(next == prev) continue;
		dfs(next, cur, to);
	}
}
void dfs1(int cur, int prev, int from, int to){
	S[from].erase(cur);
	if(!out[cur]) S[to].insert(cur);
	else S[to].insert(0);
	where[cur] = to;
	for(int i = 0; i < (int)g[cur].size(); i++){
		if(rmv[g[cur][i].second]) continue;
		int next = g[cur][i].first;
		if(next == prev) continue;
		dfs1(next, cur, from, to);
	}
}
int main(){
	scanf("%d %d %d", &n, &m, &q);
	for(int i = 1; i <= n; i++){
		scanf("%d", &per[i]);
		p[i] = i; sz[i] = 1;
	}
	for(int i = 1; i <= m; i++){
		scanf("%d %d", &u[i], &v[i]);
		u[i] = per[u[i]];
		v[i] = per[v[i]];
	}
	for(int i = 0; i < q; i++){
		scanf("%d %d", &qi[i], &val[i]);
		if(qi[i] == 2) rmv[val[i]] = true;
		else val[i] = per[val[i]];
	}
	for(int i = 1; i <= m; i++){
		if(rmv[i]) continue;
		join(u[i], v[i]);
	}
	for(int i = q-1; i >= 0; i--){
		if(qi[i] == 2){
			//ru[i] = find(u[val[i]]);
			//rv[i] = find(v[val[i]]);
			int x = u[val[i]], y = v[val[i]];
			if(find(x) == find(y)){
				su[i] = sv[i] = -1;
				continue;
			}
			su[i] = sz[find(x)];
			sv[i] = sz[find(y)];
			g[x].pb(mp(y,val[i]));
			g[y].pb(mp(x,val[i]));
			join(x, y);

		}
	}
	for(int i = 1; i <= n; i++){
		p[i] = i; sz[i] = 1;
	}
	for(int i = 1; i <= n; i++){
		for(int j = 0; j < (int)g[i].size(); j++){
			int x = i, y = g[i][j].first;
			join(x, y);
		}
	}
	for(int i = 1; i <= m; i++){
		int x = u[i], y = v[i];
		if(find(x) == find(y)) continue;
		g[x].pb(mp(y,i)); g[y].pb(mp(x,i));
		join(x, y);
	}
	ss = 0;
	memset(V, false, sizeof V);
	for(int i = 1; i <= n; i++){
		if(!V[i]) dfs(i, i, ss++);
	}
	for(int i = 1; i <= m; i++) rmv[i] = false;
	for(int i = 0; i < q; i++){
		if(qi[i] == 1){
			int cur = val[i];
			int w = where[cur];
			int ans = *S[w].rbegin();
			printf("%d\n", ans);
			if(ans){
				out[ans] = true;
				S[w].erase(ans);
				S[w].insert(0);
			}
		}else{
			rmv[val[i]] = true;
			if(su[i] == -1) continue;
			int ei = val[i];
			if(su[i] < sv[i]){
				dfs1(u[ei], u[ei], where[u[ei]], ss++);
			}else{
				dfs1(v[ei], v[ei], where[v[ei]], ss++);
			}
		}
	}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define F first
#define S second
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define per(i, a, b) for(int i = b-1; i>=a ; i--)
#define trav(a, x) for(auto& a : x)
#define allin(a , x) for(auto a : x)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<ll> vl;
typedef vector<pii> vpi;
typedef pair<ll,ll> pll;
typedef vector<string> vs;
typedef vector<pll> vpl;
typedef vector<int> vi;

const int N = 500005;

int p[N] , n, m,q,pai[N],peso[N];
set<int> comp[N];
map<int, vi> fromsmall[N];
struct snapshot{
	int psx, psy, x,y;
};
vector<snapshot> torb;
int fd(int x){
	return pai[x] == x ? x : fd(pai[x]);
}
bool join(int u , int v){
	u = fd(u) , v = fd(v);
	if(u == v)
		return false;
	if(peso[u] > peso[v])
		swap(u,v);
	torb.push_back({peso[u] , peso[v] , u , v});
	pai[u] = v, peso[v] += peso[u];
	for(auto w : comp[u])
		comp[v].insert(w) , fromsmall[v][u].push_back(w);
	comp[u].clear();
	return true;
}
void rollback(){
	if(sz(torb)){
		auto u = torb.back();
		torb.pop_back();
		pai[u.x] = u.x , pai[u.y] = u.y;
		peso[u.y] -= peso[u.x];
		for(auto w : fromsmall[u.y][u.x]){
			if(comp[u.y].count(w)){
				comp[u.y].erase(w);
				comp[u.x].insert(w);
			}
		}
		fromsmall[u.y].erase(u.x);
	}
}
pii edge[N];
struct querys{
	int a , b , mark = 0;
} Q[N];
set<int> curr;
int rev[N];
int32_t main(){
	scanf("%d%d%d" , &n, &m , &q);
	rep(i,1,n+1)
		scanf("%d" , &p[i]) , rev[p[i]] = i;
	rep(i,1,m+1)
		scanf("%d%d" , &edge[i].F , &edge[i].S) , curr.insert(i);
	rep(i,1,q+1){
		scanf("%d%d" , &Q[i].a,  &Q[i].b);
		if(Q[i].a == 2){
			curr.erase(Q[i].b);
		}
	}
	for(auto w : curr){
		Q[++q] = {2,w};
	}
	rep(i,1,n+1){
		pai[i] = i , peso[i] = 1 , comp[i].insert(p[i]);
	}
	per(i,1,q+1){
		if(Q[i].a == 2){
			if(join(edge[Q[i].b].F , edge[Q[i].b].S))
				Q[i].mark = 1;
		}
	}
	rep(i,1,q+1){
		if(Q[i].a == 1){
			int ff = fd(Q[i].b);
			if(sz(comp[ff])){
				auto best = *prev(end(comp[ff]));
				comp[ff].erase(best);
				printf("%d\n" , best);
			}
			else{
				printf("%d\n" , 0);
			}
		}
		else{
			if(Q[i].mark)
				rollback();
		}
	}
}

#include <bits/stdc++.h>
#define int long long
using namespace std;

#define mp make_pair
#define mt make_tuple
#define pb push_back
#define ms(v, x) memset((v), (x), sizeof(v))
#define all(v) (v).begin(), (v).end()
#define ff first
#define ss second
#define iopt ios::sync_with_stdio(false); cin.tie(0)

int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
int power(int x, int p, int MOD) {
    if(p == 0) return 1%MOD;
    if(p == 1) return x%MOD;
    int res = power(x, p/2, MOD);
    res = (long long)res*res%MOD;
    if(p&1) res = (long long)res*x%MOD;
    return res;
}

typedef pair<int, int> ii;
typedef long double LD;
typedef vector<int> vi;

const int N = 200010;
const int M = 500005;

struct Query {
    int type, id;
};

int no_inv[N], label[N];
int root(int u) {
    return no_inv[u];
}

struct Node;
int node_ptr = 0;
Node *no;

struct Node {
    vector<int> m;
    int child = -1;
    int poll(int id) {
        int res = 0;
        while(!m.empty()) {
            int u = m.back();
            m.pop_back();
            if(no_inv[u] == id && label[u]) {
                res = label[u];
                label[u] = 0;
                break;
            }
        }
        return res;
    }
    void split() {
        for(int x : no[child].m) {
            no_inv[x] = child;
        }
    }
};

int make_node() {
    return node_ptr++;
}

ii ed[M];
bool deleted[M];
Query qrs[M];
int ans[M];

// before
vector<int> adj[N];
bool vis[N];
int dfs_node;
void dfs(int u) {
    if(vis[u]) return;
    vis[u] = 1;
    no[dfs_node].m.pb(u);
    no_inv[u] = dfs_node;
    for(int v : adj[u])
        dfs(v);
}

int32_t main(){
    iopt;
    int n, m, q;
    cin >> n >> m >> q;
    no = new Node[N];

    for(int i = 0; i < n; i++) {
        cin >> label[i];
    }

    for(int i = 0; i < m; i++) {
        cin >> ed[i].ff >> ed[i].ss;
        ed[i].ff--, ed[i].ss--;
    }

    for(int i = 0; i < q; i++) {
        cin >> qrs[i].type >> qrs[i].id;
        qrs[i].id--;
        if(qrs[i].type == 2)
            deleted[qrs[i].id] = true;
    }

    for(int i = 0; i < m; i++) {
        if(!deleted[i]) {
            adj[ed[i].ff].pb(ed[i].ss);
            adj[ed[i].ss].pb(ed[i].ff);
        }
    }

    for(int i = 0; i < n; i++) {
        if(!vis[i]) {
            dfs_node = make_node();
            dfs(i);
        }
    }

    memset(deleted, 0, sizeof deleted);

    for(int i = q-1; i >= 0; i--) {
        if(qrs[i].type == 2) {
            ii& e = ed[qrs[i].id];
            int a = root(e.ff), b = root(e.ss);
            if(a != b) {
                // merge
                int m_no = make_node();
                if(no[a].m.size() < no[b].m.size()) swap(a, b);
                no[a].child = b;
                copy(all(no[b].m), back_inserter(no[a].m));
                for(int x : no[b].m) no_inv[x] = a;
                deleted[qrs[i].id] = true;
            }
        }
    }

    for(int i = 0; i < node_ptr; i++) {
        sort(all(no[i].m), [](int a, int b) {
            return label[a] < label[b];
        });
    }

    for(int i = 0; i < q; i++) {
        if(qrs[i].type == 1) {
            int u = qrs[i].id;
            u = root(u);
            cout << no[u].poll(u) << "\n";
        } else if(deleted[qrs[i].id]) {
            int u = root(ed[qrs[i].id].ff);
            assert(no[u].child != -1);
            no[u].split();
        }
    }
}

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;

#define sc scanf
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int Mod = 1e9 + 7;
const int N = 5e5 + 100;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % Mod; b >>= 1; t = (t*t) % Mod; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }

struct node
{
	int id, w;
	bool operator < (const node &oth) const {
		return w > oth.w;
	}
};
struct Ask
{
	int op, x;
}qi[N];
pir eg[N];
set <node> s[N];
int fa[N], sz[N], n, m, q;
int a[N];
bool vis[N];
stack <pir> st;

void Init() {
	for (int i = 1; i <= n; i++)
		fa[i] = i, sz[i] = 1;
}
int Find(int x) {
	while (x != fa[x])
		x = fa[x];
	return x;
}
void Merge(int x, int y) {
	x = Find(x);
	y = Find(y);
	if (x == y) {
		st.push({ 0, 0 });
		return;
	}
	if (sz[x] > sz[y])
		swap(x, y);
	fa[x] = y;
	st.push({ x, y });
	sz[y] += sz[x];
	for (auto it : s[x])
		s[y].insert(it);
}
void Cancle() {
	int x = st.top().first, y = st.top().second;
	st.pop();
	if (!x && !y)
		return;
	fa[x] = x;
	sz[y] -= sz[x];
	for (auto it : s[x]) {
		auto v = it;
		if (s[y].find(v) != s[y].end())
			s[y].erase(v);
	}
}

int main()
{
	cin >> n >> m >> q;
	Init();
	for (int i = 1; i <= n; i++)
		sc("%d", &a[i]), s[i].insert({ i, a[i] });
	for (int i = 1; i <= m; i++)
		sc("%d %d", &eg[i].first, &eg[i].second);
	for (int i = 1; i <= q; i++) {
		sc("%d %d", &qi[i].op, &qi[i].x);
		if (qi[i].op == 2)
			vis[qi[i].x] = true;
	}
	for (int i = 1; i <= m; i++)
		if (!vis[i])
			Merge(eg[i].first, eg[i].second);
	for (int i = q; i >= 1; i--) {
		if (qi[i].op == 1)
			continue;
		int u = eg[qi[i].x].first;
		int v = eg[qi[i].x].second;
		Merge(u, v);
	}

	for (int i = 1; i <= q; i++) {
		int op = qi[i].op, x = qi[i].x;
		if (op == 1) {
			int u = Find(x);
			if (s[u].empty()) {
				printf("%d\n", a[u]);
				a[u] = 0;
				continue;
			}
			int v = s[u].begin()->id;
			printf("%d\n", s[u].begin()->w);
			s[u].erase({ v, a[v] });
			a[v] = 0;
			s[u].insert({ v, a[v] });
		}
		else
			Cancle();
	}
	return 0;  // 改数组大小!!!用pair记得改宏定义!!!
}

/*
	Name:
	Author: Gensokyo_Alice
	Date:
	Description:
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <map>
#include <set>

using namespace std;

typedef long long ll;
const ll MAXN = 1e6+10;

ll N, M, Q, val[MAXN], id[MAXN], tag[MAXN], fa[MAXN], vis[MAXN];
ll ed[MAXN], be[MAXN], a[MAXN], num;
struct ed {
	ll x, y;
} e[MAXN];
struct opt {
	ll kind, k;
} o[MAXN];
struct edge {
	ll nt, to;
} E[MAXN];
struct lk {
	ll pre, nxt;
} t[MAXN];
struct nod {
	ll l, r, maxn, pos;
} tr[MAXN];
struct ww {
	ll l, r;
} kk[MAXN];

ll find_(ll);
ll ask(ll, ll, ll);
void ins(ll, ll);
void build(ll, ll, ll);
void updata(ll);
void dfs(ll, ll);

int main() {
	scanf("%lld%lld%lld", &N, &M, &Q);
	for (ll i = 1; i <= N; i++) scanf("%lld", a+i), fa[i] = i, ed[i] = i, be[i] = i;
	for (ll i = 1; i <= M; i++) scanf("%lld%lld", &e[i].x, &e[i].y);
	for (ll i = 1; i <= Q; i++) {
		scanf("%lld%lld", &o[i].kind, &o[i].k);
		if (o[i].kind == 2) tag[o[i].k] = 1;
	}
	for (ll i = 1; i <= M; i++) {
		if (!tag[i]) {
			ll fx = find_(e[i].x), fy = find_(e[i].y);
			if (fx != fy) {
				fa[fx] = fy;
				t[ed[fx]].nxt = be[fy];
				t[be[fy]].pre = ed[fx];
				be[fy] = be[fx];
			}
		}
	}
	for (ll i = Q; i; i--) {
		if (o[i].kind == 2) {
			ll tmp = o[i].k;
			ll fx = find_(e[tmp].x), fy = find_(e[tmp].y);
			if (fx == fy) {
				tag[tmp] = 0;
			} else {
				fa[fx] = fy;
				t[ed[fx]].nxt = be[fy];
				t[be[fy]].pre = ed[fx];
				be[fy] = be[fx];
				// onion
			}
		} else {
			ll x = find_(o[i].k);
			kk[i].l = be[x];
			kk[i].r = ed[x];
		}
	}
	for (ll i = 1; i <= N; i++) if (!t[i].pre) dfs(i, 0);
	build(1, 1, num);
	for (ll i = 1; i <= Q; i++) {
		if (o[i].kind == 1) {
			ll tem;
			printf("%lld\n", val[tem = ask(1, id[kk[i].l], id[kk[i].r])]);
			ins(1, tem);
		}
	}
    return 0;
}

ll ask(ll node, ll a, ll b) {
	if (a <= tr[node].l && tr[node].r <= b) return tr[node].pos;
	ll mid = (tr[node].l + tr[node].r) >> 1, ret = 0;
	if (a <= mid) {
		ll tem = ask(node << 1, a, b);
		if (val[tem] > val[ret]) ret = tem;
	}
	if (mid < b) {
		ll tem = ask(node << 1 | 1, a, b);
		if (val[tem] > val[ret]) ret = tem;
	}
	return ret;
}

void ins(ll node, ll pos) {
	if (tr[node].l == pos && tr[node].r == pos) {
		tr[node].maxn = 0;
		val[tr[node].pos] = 0;
		return;
	}
	ll mid = (tr[node].l + tr[node].r) >> 1;
	if (pos <= mid) ins(node << 1, pos);
	else ins(node << 1 | 1, pos);
	updata(node);
}

void build(ll node, ll l, ll r) {
	tr[node].l = l;
	tr[node].r = r;
	tr[node].maxn = 0;
	tr[node].pos = 0;
	if (l == r) {
		tr[node].maxn = val[l];
		tr[node].pos = l;
		return;
	}
	ll mid = (l + r) >> 1;
	build(node << 1, l, mid);
	build(node << 1 | 1, mid + 1, r);
	updata(node);
}

void updata(ll node) {
	if (tr[node << 1 | 1].maxn > tr[node << 1].maxn) {
		tr[node].maxn = tr[node << 1 | 1].maxn;
		tr[node].pos = tr[node << 1 | 1].pos;
	} else {
		tr[node].maxn = tr[node << 1].maxn;
		tr[node].pos = tr[node << 1].pos;
	}
}

void dfs(ll n, ll ff) {
	vis[n] = 1, id[n] = ++num, val[num] = a[n];
	if (t[n].nxt && !vis[t[n].nxt]) dfs(t[n].nxt, n) ;
}

ll find_(ll x) {return fa[x] == x ? x : fa[x] = find_(fa[x]);}

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/priority_queue.hpp>
//#pragma GCC optimize("O3")
//#pragma GCC target("sse4")
//#pragma GCC target("avx2")

#define deb(x) cout << #x << " = " << x << "\n"
#define all(x) (x).begin(), (x).end()
#define len(x) (int) x.size()
#define lsb(x) (x) & -(x)
#define l(x) (x << 1) + 1
#define r(x) (x << 1) + 2
#define v(x) (int)(x - 'a')

#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define lb lower_bound
#define ub upper_bound

using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair <int, int> pii;
typedef pair <ld, ld> pld;
typedef pair <ll, ll> pll;

template <class T1, class T2 = less <T1>> using pb_heap = __gnu_pbds::priority_queue <T1, T2, binary_heap_tag>;
template <class T1, class T2 = null_type, class T3 = less <T1>> using pb_map = tree <T1, T2, T3, rb_tree_tag, tree_order_statistics_node_update>;
template <class T1, class T2 = null_type, class T3 = hash <T1>> using pb_umap = gp_hash_table <T1, T2, T3>;
template <class T1, class T2, class T3 = hash <T1>> using umap = unordered_map <T1, T2, T3>;
template <class T> using uset = unordered_set <T>;
template <class T> using vec = vector <T>;

const ll infll = numeric_limits <ll>::max() >> 1;
const int inf = numeric_limits <int>::max() >> 1;
const int N = 5e5 + 1;
int n, m, q, curr;
int arr[N];
int ind[N];

bool vis[N];

pii qry[N];
pii edge[N];

vec <int> roots;

struct Graph {
    int lef[N];
    int rig[N];
    vec <int> adj[N];
} graph;

struct Node {
    int l, r;
    pii mxm;
} node[N << 2];

struct Dsu {
    int par[N];
} dsu;

int root(int u) {
    return dsu.par[u] == u? u: dsu.par[u] = root(dsu.par[u]);
}

void unite(int u, int v) {
    u = root(u);
    v = root(v);
    int p = ++n;
    graph.adj[p].pb(u);
    graph.adj[p].pb(v);
    dsu.par[p] = p;
    dsu.par[u] = p;
    dsu.par[v] = p;
}

void merge(int id, int l, int r) {
    node[id].mxm = max(node[l].mxm, node[r].mxm);
}

void build(int id, int l, int r) {
    node[id].l = l;
    node[id].r = r;
    if(l == r) {
        node[id].mxm.xx = arr[ind[l]];
        node[id].mxm.yy = l;
        return;
    }
    int q = l + r >> 1;
    build(l(id), l, q);
    build(r(id), q + 1, r);
    merge(id, l(id), r(id));
}

void erase(int id, int i) {
    if(node[id].l == node[id].r) {
        node[id].mxm.xx = 0;
        return;
    }
    int q = node[id].l + node[id].r >> 1;
    if(i <= q) {
        erase(l(id), i);
    } else {
        erase(r(id), i);
    }
    merge(id, l(id), r(id));
}

pii query(int id, int l, int r) {
    if(node[id].l == l && node[id].r == r) {
        return node[id].mxm;
    }
    pii res = {0, 0};
    int q = node[id].l + node[id].r >> 1;
    if(l <= q) {
        res = max(res, query(l(id), l, min(q, r)));
    }
    if(r > q) {
        res = max(res, query(r(id), max(q + 1, l), r));
    }
    return res;
}

void dfs(int u) {
    static int t = 0;
    ind[++t] = u;
    graph.lef[u] = t;
    for(int v: graph.adj[u]) {
        dfs(v);
    }
    graph.rig[u] = t;
}

void input() {
    cin >> n >> m >> q;
    for(int i = 1; i <= n; ++i) {
        cin >> arr[i];
    }
    for(int i = 1; i <= m; ++i) {
        int u; cin >> u;
        int v; cin >> v;
        edge[i] = {u, v};
    }
    for(int i = 1; i <= q; ++i) {
        cin >> qry[i].xx;
        cin >> qry[i].yy;
        if(qry[i].xx == 2) {
            vis[qry[i].yy] = 1;
        }
    }
}

void solve() {
    for(int i = 1; i <= n; ++i) {
        dsu.par[i] = i;
    }
    for(int i = 1; i <= m; ++i) {
        if(!vis[i]) {
            int u = edge[i].xx;
            int v = edge[i].yy;
            unite(u, v);
        }
    }
    for(int i = q; i >= 1; --i) {
        if(qry[i].xx == 1) {
            roots.pb(root(qry[i].yy));
        } else {
            int u = edge[qry[i].yy].xx;
            int v = edge[qry[i].yy].yy;
            if(root(u) == root(v)) {
                continue;
            }
            unite(u, v);
        }
    }
    for(int i = 1; i <= n; ++i) {
        if(root(i) == i) {
            dfs(i);
        }
    }
    build(0, 1, n);
    reverse(all(roots));
    if(n > 100) {
        cout << n << " <<\n";
        return;
    }
    for(int e: roots) {
        pii p = query(0, graph.lef[e], graph.rig[e]);
        erase(0, p.yy);
        cout << p.xx << "\n";
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    input();
    solve();
}

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>

template <typename Tp> void read(Tp &res){
	static char ch; ch = getchar(), res = 0;
	while(!isdigit(ch)) ch = getchar();
	while(isdigit(ch)) res = res * 10 + ch - 48, ch = getchar();
}

const int MAXN = 2e5 + 19, MAXM = 3e5 + 19;

int n, m, q, fa[MAXN], birth[MAXM], p[MAXN], opt[MAXN], arg[MAXN];
int getf(int node){return node == fa[node] ? node : fa[node] = getf(fa[node]);}
std::vector<int> mt[MAXN];
std::pair<int, int> G[MAXM];
bool vist[MAXN];

int main(){
	read(n), read(m), read(q);
	for(int i = 1; i <= n; ++i) read(p[i]), fa[i] = i, mt[i].push_back(i);
	for(int i = 1; i <= m; ++i) read(G[i].first), read(G[i].second);
	for(int i = 1; i <= q; ++i){
		read(opt[i]), read(arg[i]);
		if(opt[i] == 2) vist[arg[i]] = 1;
	}
	for(int i = 1; i <= m; ++i){
		int a = G[i].first, b = G[i].second;
		a = getf(a), b = getf(b);
		if(vist[i] || a == b) continue;
		birth[i] = b;
		for(int j : mt[b]) mt[a].push_back(j);
		fa[b] = a;
	}
	for(int i = q; i >= 1; --i)
		if(opt[i] == 2){
			int a = G[arg[i]].first, b = G[arg[i]].second;
			a = getf(a), b = getf(b);
			if(a == b) continue;
			birth[arg[i]] = b;
			for(int j : mt[b]) mt[a].push_back(j);
			fa[b] = a;
		}
	for(int i = 1; i <= n; ++i) std::sort(mt[i].begin(), mt[i].end(), [](const int &a, const int &b){return p[a] < p[b];});
	for(int i = 1; i <= q; ++i){
		if(opt[i] == 1){
			int a = getf(arg[i]);
			while(!mt[a].empty() && getf(mt[a].back()) != a) mt[a].pop_back();
			if(mt[a].empty()) puts("0");
			else printf("%d\n", p[mt[a].back()]), fa[mt[a].back()] = 0;
		}
		else{
			int a = birth[arg[i]];
			for(int j : mt[a]) if(fa[j]) fa[j] = a;
		}
	}
	return 0;
}

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#define maxn 300005
#define lson (now<<1)
#define rson ((now<<1)|1)
#define mid ((nl+nr)>>1)
using namespace std;
typedef long long ll;
int n,m,q;
int a[maxn];
int vis[maxn];
int u[maxn],v[maxn];
int op[maxn],val[maxn];
int fa[maxn],id[maxn];
int getfa(int now)
{
	return fa[now]==now ? now : fa[now]=getfa(fa[now]);
}
int tot,cnt=n;
int to[maxn<<2],nex[maxn<<2],head[maxn<<1];
void add(int x,int y)
{
	to[++tot]=y;  nex[tot]=head[x]; head[x]=tot;
}
int l[maxn<<1],r[maxn<<1],dfn[maxn<<1];
int dat1[maxn<<3],dat2[maxn<<3];
void pushup(int now)
{
	if(dat1[lson]<dat1[rson])
		dat1[now]=dat1[rson],dat2[now]=dat2[rson];
	else
		dat1[now]=dat1[lson],dat2[now]=dat2[lson];
}
void update(int ql,int val,int nl,int nr,int now)
{
	if(nl==nr)
	{
		dat1[now]=val;
		dat2[now]=nl;
		return;
	}
	if(ql<=mid)
		update(ql,val,nl,mid,lson);
	else
		update(ql,val,mid+1,nr,rson);
	pushup(now);
}
void dfs(int now,int fa)
{
	vis[now]=1;
	dfn[now]=++tot;
	l[now]=tot;

	if(now<=n)
		update(tot,a[now],1,cnt,1);

	for(int i=head[now];i;i=nex[i])
	if(to[i]!=fa)
		dfs(to[i],now);
	r[now]=tot;
}
pair<int,int> query(int ql,int qr,int nl,int nr,int now)
{
	if(ql<=nl && nr<=qr)
		return {dat1[now],dat2[now]};
	pair<int,int> ans={-1,-1};
	if(ql<=mid)
		ans=max(ans,query(ql,qr,nl,mid,lson));
	if(mid<qr)
		ans=max(ans,query(ql,qr,mid+1,nr,rson));
	return ans;
}
int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),fa[i]=i;
	for(int i=1;i<=m;i++)
		scanf("%d%d",&u[i],&v[i]);
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&op[i],&val[i]);
		if(op[i]==2)
			vis[val[i]]=1;
	}

	for(int i=1;i<=m;i++)
	if(!vis[i])
	{
		int xx=getfa(u[i]),yy=getfa(v[i]);
		if(xx!=yy)
		{
			fa[xx]=yy;
			add(u[i],v[i]);
			add(v[i],u[i]);
		}
	}

	cnt=n;

	for(int i=q;i>=1;i--)
	{
		if(op[i]==1)//精髓
			val[i]=getfa(val[i]);
		else
		{
			int xx=getfa(u[i]),yy=getfa(v[i]);
			if(xx!=yy)
			{
				cnt++;
				fa[xx]=cnt;
				fa[yy]=cnt;
				fa[cnt]=cnt;
				add(cnt,xx);
				add(cnt,yy);
			}
		}
	}
	memset(vis,0,sizeof(vis));

	tot=0;
	for(int i=1;i<=n;i++)
		if(!vis[getfa(i)])
			dfs(getfa(i),-1);

	for(int i=1;i<=q;i++)
	{
		if(op[i]==1)
		{
			pair<int,int> res=query(l[val[i]],r[val[i]],1,cnt,1);
			printf("%d\n",res.first);
			update(res.second,0,1,cnt,1);
		}
	}
}

#include <bits/stdc++.h>

#define f first
#define s second
#define pb push_back
#define mp make_pair

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;

const int N = (int)5e5 + 123, inf = 1e9, mod = 1e9 + 7;
const ll INF = 1e18;

int n, m, q, k, a[N], b[N], type[N], val[N], ans[N], lim[N];
int p[N], sz[N];
set < pii > st[N];
bool skip[N], del[N], used[N];
pii t[N];
vector< int > vec[N];

int get(int v){
	if(p[v] == v)
		return v;
	return get(p[v]);
}
void Merge(int i){
	//cerr << i << " " ;
	if(used[i]){
	//	cerr << "- " << a[i] << " " << b[i] << " ";
		if(skip[i]){
	//		cerr << "skip";
			skip[i] = 0;
		}else{
			k--;
			int v = t[k].f;
			int u = t[k].s;
			for(auto it : st[u])
				st[v].erase(it);
			sz[v] -= sz[u];
			p[u] = u;
		}
	}else{
	//	cerr << "+ " << a[i] << " " << b[i] << " ";
		int v = get(a[i]);
		int u = get(b[i]);
		if(v == u){
	//		cerr << "skip";
			skip[i] = 1;
		}else{
			if(sz[v] < sz[u])
				swap(v, u);
			for(auto it : st[u])
				if(!del[it.s])
					st[v].insert(it);
			sz[v] += sz[u];
			p[u] = v;
			t[k++] = {v, u};
		}
	}
	//cerr << endl;
	used[i] ^= 1;
}
void fix(int v){
	while(!st[v].empty()){
		int i = st[v].begin() -> s;
		if(del[i])
			st[v].erase(st[v].begin());
		else
			break;
	}
}
int main()
{
	scanf("%d%d%d", &n, &m, &q);
	for(int i = 1; i <= n; i++)
		scanf("%d", &p[i]);
	for(int i = 1; i <= m; i++)
		scanf("%d%d", &a[i], &b[i]);
	for(int i = 1; i <= q; i++)
		scanf("%d%d", &type[i], &val[i]);
	for(int i = 1; i <= m; i++)
		lim[i] = q + 1;
	for(int i = 1; i <= q; i++)
		if(type[i] == 2)
			lim[val[i]] = i;
	for(int i = 1; i <= m; i++)
		vec[val[i]].pb(i);
	for(int i = 1; i <= n; i++){
		st[i].insert({n - p[i], i});
		p[i] = i, sz[i] = 1;
	}
	for(int i = q + 1; i >= 1; i--)
		for(auto j : vec[i])
			Merge(j);
	for(int i = 1; i <= q; i++){
	    reverse(vec[i].begin(), vec[i].end());
		for(auto j : vec[i])
			Merge(j);
		if(type[i] != 1)
			continue;
		int v = val[i];
		v = get(v);
		fix(v);
		if(st[v].empty()){
			ans[i] = 0;
			printf("0\n");
		}else{
			ans[i] = st[v].begin() -> f;
			printf("%d\n", n - ans[i]);
			del[st[v].begin() -> s] = 1;
		}
	}
}

#include<algorithm>
#include<cstdio>
#include<vector>
#define pb push_back
#define MaxN 200500
using namespace std;
vector<int> p[MaxN];
int f[MaxN],c[MaxN];
int find(int u)
{return f[u]==u ? u : find(f[u]);}
void merge(int &u,int &v)
{
  u=find(u);v=find(v);
  if (u==v)return ;
  if (c[v]>c[u])swap(u,v);
  c[f[u]=v]+=c[u];
  for (int j=0;j<p[u].size();j++)
    p[v].pb(p[u][j]);
}
int w[MaxN],top[MaxN];
bool del[300500];
int qry(int u)
{
  while(p[u].size()&&(del[p[u].back()]||top[p[u].back()]!=u))
    p[u].pop_back();
  if (p[u].empty())return 0;
  int ret=p[u].back();
  del[ret]=1;
  return ret;
}
struct Data{int op,x;}b[500500];
struct Line{int u,v;}l[300500];
int n,m,q;
int main()
{
  scanf("%d%d%d",&n,&m,&q);
  for (int i=1;i<=n;i++){
    scanf("%d",&w[i]);
    p[i].pb(w[i]);
    c[f[i]=i]=1;
  }
  for (int i=1;i<=m;i++)
    scanf("%d%d",&l[i].u,&l[i].v);
  for (int i=1;i<=q;i++){
    scanf("%d%d",&b[i].op,&b[i].x);
    if (b[i].op==2)del[b[i].x]=1;
  }
  for (int i=1;i<=m;i++){
    if (del[i])continue ;
    merge(l[i].u,l[i].v);
  }
  for (int i=q;i;i--)
    if (b[i].op==2)
      merge(l[i].u,l[i].v);
  for (int i=1;i<=n;i++){
    sort(p[i].begin(),p[i].end());
    del[i]=0;top[w[i]]=find(i);
  }
  for (int i=1;i<=q;i++){
  	if (b[i].op==1)
      printf("%d\n",qry(find(b[i].x)));
  	else {
  	  if (l[i].u==l[i].v)continue;
  	  int u=l[i].u;
  	  for (int j=0;j<p[u].size();j++)
        top[p[u][j]]=u;
      f[u]=u;
  	}
  }return 0;
}

#pragma region Macros
#pragma GCC optimize("O3")
#pragma GCC target("avx2,avx")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
#define ll long long
#define ld long double
#define rep2(i, a, b) for(ll i = a; i <= b; ++i)
#define rep(i, n) for(ll i = 0; i < n; ++i)
#define rep3(i, a, b) for(ll i = a; i >= b; --i)
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pb push_back
#define eb emplace_back
#define vi vector<int>
#define vll vector<ll>
#define vpi vector<pii>
#define vpll vector<pll>
#define overload2(_1, _2, name, ...) name
#define vec(type, name, ...) vector<type> name(__VA_ARGS__)
#define VEC(type, name, size)                                                                                \
    vector<type> name(size);                                                                                \
    IN(name)
#define vv(type, name, h, ...) vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define VV(type, name, h, w)                                                                                \
    vector<vector<type>> name(h, vector<type>(w));                                                                                \
    IN(name)
#define vvv(type, name, h, w, ...) vector<vector<vector<type>>> name(h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)                                                                                \
    vector<vector<vector<vector<type>>>> name(a, vector<vector<vector<type>>>(b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))
#define fi first
#define se second
#define all(c) begin(c), end(c)
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
using namespace std;
string YES[2] = {"NO", "YES"};
string Yes[2] = {"No", "Yes"};
string yes[2] = {"no", "yes"};
template <class T> using pq = priority_queue<T>;
template <class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
#define si(c) (int)(c).size()
#define INT(...)                                                                                \
    int __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define LL(...)                                                                                \
    ll __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define STR(...)                                                                                \
    string __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define CHR(...)                                                                                \
    char __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define DBL(...)                                                                                \
    double __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
int scan() { return getchar(); }
void scan(int &a) { cin >> a; }
void scan(long long &a) { cin >> a; }
void scan(char &a) { cin >> a; }
void scan(double &a) { cin >> a; }
void scan(string &a) { cin >> a; }
template <class T, class S> void scan(pair<T, S> &p) { scan(p.first), scan(p.second); }
template <class T> void scan(vector<T> &);
template <class T> void scan(vector<T> &a) {
    for(auto &i : a) scan(i);
}
template <class T> void scan(T &a) { cin >> a; }
void IN() {}
template <class Head, class... Tail> void IN(Head &head, Tail &... tail) {
    scan(head);
    IN(tail...);
}
template <class T, class S> inline bool chmax(T &a, S b) {
    if(a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T, class S> inline bool chmin(T &a, S b) {
    if(a > b) {
        a = b;
        return 1;
    }
    return 0;
}
vi iota(int n) {
    vi a(n);
    iota(all(a), 0);
    return a;
}
template <typename T> vi iota(vector<T> &a, bool greater = false) {
    vi res(a.size());
    iota(all(res), 0);
    sort(all(res), [&](int i, int j) {
        if(greater) return a[i] > a[j];
        return a[i] < a[j];
    });
    return res;
}
#define UNIQUE(x) sort(all(x)), x.erase(unique(all(x)), x.end())
vector<pll> factor(ll x) {
    vector<pll> ans;
    for(ll i = 2; i * i <= x; i++)
        if(x % i == 0) {
            ans.push_back({i, 1});
            while((x /= i) % i == 0) ans.back().second++;
        }
    if(x != 1) ans.push_back({x, 1});
    return ans;
}
template <class T> vector<T> divisor(T x) {
    vector<T> ans;
    for(T i = 1; i * i <= x; i++)
        if(x % i == 0) {
            ans.pb(i);
            if(i * i != x) ans.pb(x / i);
        }
    return ans;
}
template <typename T> void zip(vector<T> &x) {
    vector<T> y = x;
    sort(all(y));
    for(int i = 0; i < x.size(); ++i) { x[i] = lb(y, x[i]); }
}
int popcount(ll x) { return __builtin_popcountll(x); }
struct Setup_io {
    Setup_io() {
        ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
        cout << fixed << setprecision(15);
    }
} setup_io;
int in() {
    int x;
    cin >> x;
    return x;
}
ll lin() {
    unsigned long long x;
    cin >> x;
    return x;
}

template <typename T> struct edge {
    int from, to;
    T cost;
    int id;
    edge(int to, T cost) : from(-1), to(to), cost(cost) {}
    edge(int from, int to, T cost) : from(from), to(to), cost(cost) {}
    edge(int from, int to, T cost, int id) : from(from), to(to), cost(cost), id(id) {}
    edge &operator=(const int &x) {
        to = x;
        return *this;
    }
    operator int() const { return to; }
};
template <typename T> using Edges = vector<edge<T>>;

using Tree = vector<vector<int>>;
using Graph = vector<vector<int>>;
template <class T> using Wgraph = vector<vector<edge<T>>>;
Graph getG(int n, int m = -1, bool directed = false, int margin = 1) {
    Tree res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        cin >> a >> b;
        a -= margin, b -= margin;
        res[a].emplace_back(b);
        if(!directed) res[b].emplace_back(a);
    }
    return move(res);
}
template <class T> Wgraph<T> getWg(int n, int m = -1, bool directed = false, int margin = 1) {
    Wgraph<T> res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        T c;
        cin >> a >> b >> c;
        a -= margin, b -= margin;
        res[a].emplace_back(b, c);
        if(!directed) res[b].emplace_back(a, c);
    }
    return move(res);
}

#define i128 __int128_t
#define ull unsigned long long int
#define TEST                                                                                \
    INT(testcases);                                                                                \
    while(testcases--)
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    for(auto &e : v) cout << e << " ";
    cout << endl;
    return os;
}
template <class T, class S> ostream &operator<<(ostream &os, const pair<T, S> &p) {
    cout << "(" << p.fi << ", " << p.se << ")";
    return os;
}
template <class S, class T> string to_string(pair<S, T> p) { return "(" + to_string(p.first) + "," + to_string(p.second) + ")"; }
template <class A> string to_string(A v) {
    if(v.empty()) return "{}";
    string ret = "{";
    for(auto &x : v) ret += to_string(x) + ",";
    ret.back() = '}';
    return ret;
}

void dump() { cerr << endl; }
template <class Head, class... Tail> void dump(Head head, Tail... tail) {
    cerr << to_string(head) << " ";
    dump(tail...);
}
#define endl '\n'
#ifdef _LOCAL
#undef endl
#define debug(x)                                                                                \
    cout << #x << ": ";                                                                                \
    dump(x)
#else
#define debug(x)
#endif
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

// int rnd(int n) { return uniform_int_distribution<int>(0, n - 1)(rng); }
// ll rndll(ll n) { return uniform_int_distribution<ll>(0, n - 1)(rng); }

template <typename T> static constexpr T inf = numeric_limits<T>::max() / 2;
#pragma endregion

vector<int> a;
template <typename T = int> struct UnionFind {
    vector<int> data;
    vector<set<int>> s;
    struct A {
        int x, y, datx, daty;
        A() = default;
    };
    vector<A> hist;
    int num;

    UnionFind(int n) : num(n) {
        data.assign(n, -1);
        s.resize(n);
        rep(i, n) s[i].emplace(a[i]);
    }

    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if(x == y) {
            A a;
            a.y = -1;
            hist.eb(a);
            return false;
        }
        num--;
        if(data[x] > data[y]) swap(x, y);
        hist.eb(A{x, y, data[x], data[y]});
        data[x] += data[y];
        data[y] = x;
        for(auto &e : s[y]) s[x].emplace(e);
        return true;
    }

    int find(int x) {
        if(data[x] < 0) return x;
        return (data[x] = find(data[x]));
    }

    void undo() {
        auto &a = hist.back();
        hist.pop_back();
        if(a.y == -1) { return; }
        int x = a.x, y = a.y;
        data[x] = a.datx;
        data[y] = a.daty;
        for(auto it = s[y].begin(); it != s[y].end();) {
            auto it2 = s[x].find(*it);
            if(it2 != s[x].end())
                s[x].erase(it2), it++;
            else
                it = s[y].erase(it);
        }
    }
    int get(int x) {
        x = find(x);
        if(s[x].empty())
            return 0;
        else {
            int res = *s[x].rbegin();
            s[x].erase(--s[x].end());
            return res;
        }
    }
};

int main() {
    INT(n, m, q);
    a.resize(n);
    rep(i, n) cin >> a[i];
    vector<pii> E;
    rep(i, m) {
        INT(x, y);
        x--, y--;
        E.eb(x, y);
    }
    vi used(m);
    vi edges;
    vector<pii> query;
    rep(i, q) {
        INT(t, s);
        query.eb(t, --s);
        if(t == 2) {
            edges.eb(s);
            used[s] = true;
        }
    }
    rep(i, m) if(!used[i]) edges.eb(i);
    UnionFind uf(n);
    reverse(all(edges));
    for(auto i : edges) uf.unite(E[i].fi, E[i].se);
    for(auto [t, s] : query) {
        if(t == 1) {
            int res = uf.get(s);
            if(s == 4 and n == 95) {
                dump(uf.s[uf.find(s)]);
                exit(0);
            }
            cout << res << endl;
        } else
            uf.undo();
    }
}

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,r,l) for(int i=(r);i>=(l);--i)
#define For(i,u) for(int i=hed[u],v=e[i].to;i;i=e[i].nex,v=e[i].to)
#define fi first
#define se second
#define mp make_pair
using namespace std;
const int N=2e5+10;
int f[N],sz[N],hed[N],ed,n,m,Q,id[N],opt[N],a[N],u[N],v[N],del[N];
set<pair<int,int> > s[N];bool ban[N];
struct edge{
	int to,nex;bool vis;
	edge(int _=0,int __=0):to(_),nex(__),vis(0){}
}e[N<<1];
inline void add(int u,int v){e[++ed]=edge(v,hed[u]);hed[u]=ed;}
int gfa(int x){return f[x]^x?(f[x]=gfa(f[x])):x;}
void merge(int u,int v){u=gfa(u);v=gfa(v);if(sz[u]>=sz[v]) swap(u,v);f[u]=v;sz[v]+=sz[u];}
void dfs(int u,int fa,int x,int y){
	f[u]=x;s[y].erase(mp(a[u],u));s[x].insert(mp(a[u],u));
	For(i,u) if((v^fa)&&!e[i].vis) dfs(v,u,x,y);
}
int main(){
	//freopen("in","r",stdin);
	scanf("%d%d%d",&n,&m,&Q);ed=1;
	rep(i,1,n) scanf("%d",a+i),f[i]=i,sz[i]=1;
	rep(i,1,m) scanf("%d%d",u+i,v+i);
	rep(i,1,Q) scanf("%d%d",opt+i,id+i);
	rep(i,1,Q) if(opt[i]==2) ban[id[i]]=1;
	rep(i,1,m) if(gfa(u[i])^gfa(v[i])&&!ban[i]) merge(u[i],v[i]),add(u[i],v[i]),add(v[i],u[i]);
	per(i,Q,1) if(opt[i]==2&&(gfa(u[id[i]])^gfa(v[id[i]]))){
		int x=gfa(u[id[i]]),y=gfa(v[id[i]]);
		add(u[id[i]],v[id[i]]),add(v[id[i]],u[id[i]]);
		del[i]=sz[x]<sz[y]?ed:ed-1;
	}
	rep(i,1,n) s[gfa(i)].insert(mp(a[i],i));
	rep(i,1,Q){
		if(opt[i]==1){
			int u=gfa(id[i]),x=s[u].rbegin()->se;
			printf("%d\n",a[x]);a[x]=0;
			s[u].erase(*s[u].rbegin());s[u].insert(mp(0,x));
		}
		else if(del[i]){
			int x=e[del[i]].to;e[del[i]].vis=e[del[i]^1].vis=1;
			dfs(x,0,x,gfa(x));
		}
	}
	return 0;
}

#include <bits/stdc++.h>
#define endl '\n'
#define fi first
#define se second
#define pb push_back
#define bit(s, i) (s & (1<<i))

using namespace std;

const int N = 5e5 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const long long Inf = 0x3f3f3f3f3f3f3f3f;

typedef long long ll;
typedef pair < int, int > ii;

int n, m, q, p[N], siz[N], par[N];

bool ok[N], has[N];

struct query {
	int t;
	int x;
} qry[N];

ii e[N], edge[N], cur;

vector < int > adj[N];

set < ii > st[N];

void init() {
	for(int i=1;i<=n;++i) {
		par[i] = i;
		siz[i] = 1;
	}
}

int get(int x) {
	if(x == par[x]) return x;
	return par[x] = get(par[x]);
}

bool mix(int x, int y) {
	int u = get(x);
	int v = get(y);

	if(u == v) return 0;

	if(siz[u] < siz[v]) {
		par[u] = v;
		siz[v] += siz[u];
		adj[v].pb(u);
		cur = ii(v, u);
	}
	else {
		par[v] = u;
		siz[u] += siz[v];
		adj[u].pb(v);
		cur = ii(u, v);
	}
	return 1;
}

void dfs(int v, vector < int > &res) {
	res.pb(v);
	for(int u : adj[v]) dfs(u, res);
}

int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	// freopen("trash.inp", "r", stdin);
	// freopen("trash.out", "w", stdout);

	cin >> n >> m >> q;
	init();
	for(int i=1;i<=n;++i) cin >> p[i];

	for(int i=1;i<=m;++i) {
		int u, v;
		cin >> u >> v;
		e[i] = ii(u, v);
	}

	for(int i=1;i<=q;++i) {
		cin >> qry[i].t >> qry[i].x;
		if(qry[i].t == 2) ok[qry[i].x] = true;
	}

	for(int i=1;i<=m;++i) if(!ok[i]) mix(e[i].fi, e[i].se);

	for(int i=q;i>=1;--i) if(qry[i].t == 2) {
		int u = e[qry[i].x].fi;
		int v = e[qry[i].x].se;

		if(mix(u, v)) {
			edge[i] = cur;
			has[i] = 1;
		}
	}

	for(int i=1;i<=n;++i) {
		int u = get(i);
		st[u].insert(ii(p[i], i));
	}

	for(int i=1;i<=q;++i) {
		if(qry[i].t == 1)
		{
			int u = get(qry[i].x);
			auto x = *st[u].rbegin();
			cout << p[x.se] << endl;
			st[u].erase(x);
			p[x.se] = 0;
			st[u].insert(ii(p[x.se], x.se));
		} else if (has[i]) {
			int a = edge[i].fi;
			int b = edge[i].se;

			par[b] = b;
			adj[a].pop_back();
			a = get(a);

			vector < int > res;
			dfs(b, res);

			for(int x : res) {
				st[a].erase(ii(p[x], x));
				st[b].insert(ii(p[x], x));
			}
		}
	}
}

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define ll long long
#define sz(x) ((int)(x.size()))
#define M1 1000000007LL
#define M2 998244353LL

typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<ll> vll;
typedef vector<pll> vpl;

#define MAXN 200010
#define MAXM 300010
#define MAXQ 500010
int p[MAXN],ip[MAXN],g[MAXN];
bool del[MAXM],rm[MAXN];
pii edge[MAXM],query[MAXQ],split[MAXM];
set<int> S[MAXN];
vi mergeList[MAXN];

int find(int u) {
	if (g[u] > 0) {
		g[u] = find(g[u]);
		return g[u];
	}
	return u;
}

void buildSet(int u) {
	S[u].insert(p[u]);
	for (int v : mergeList[u]) {
		for (int pv : S[v]) {
			S[u].insert(pv);
		}
	}
}

void merge(int u,int v,int k) {
	u = find(u);
	v = find(v);
	if (u == v) {
		split[k] = pii(0,0);
	}
	else if (g[u] < g[v]) {
		split[k] = pii(u,v);
		buildSet(v);
		mergeList[u].pb(v);
		g[u] += g[v];
		g[v] = u;
	}
	else {
		split[k] = pii(v,u);
		buildSet(u);
		mergeList[v].pb(u);
		g[v] += g[u];
		g[u] = v;
	}
}

void handleQuery(int v) {
	int gv = find(v);
	if (S[gv].empty()) {
		cout << 0 << endl;
	}
	else {
		auto it = S[gv].rbegin();
		int v = ip[*it];
		cout << *it << endl;
		S[gv].erase(*it);
		rm[v] = true;
	}
}

void handleSplit(int k) {
	int u = split[k].first,v = split[k].second;
	if (u == 0) {
		return;
	}
	vi splitList;
	for(int pv : S[v]) {
		splitList.pb(pv);
	}
	for (int pv : splitList) {
		g[ip[pv]] = v;
		if (S[u].count(pv)) {
			S[u].erase(pv);
		}
		if (rm[v]){
			S[v].erase(pv);
		}
	}
	g[v] = -sz(splitList);
}

int main() {
	ios::sync_with_stdio(false);cin.tie(0);

	int n,m,q;
	cin >> n >> m >> q;
	for (int i=1; i<=n; i++) {
		cin >> p[i];
		ip[p[i]] = i;
		rm[i] = false;
		g[i] = -1;
	}

	int u,v;
	for (int i=1; i<=m; i++) {
		cin >> u >> v;
		edge[i] = pii(u,v);
		del[i] = false;
	}

	for (int i=1; i<=q; i++) {
		int qt;
		cin >> qt >> v;
		if (qt == 2) {
			del[v] = true;
		}
		query[i] = pii(qt,v);
	}

	for (int i=1; i<=m; i++) {
		if (del[i]) {
			continue;
		}
		u = edge[i].first,v = edge[i].second;
		merge(u,v,i);
	}

	for (int i=q; i>=1; i--) {
		int qt = query[i].first;
		if (qt == 2) {
			int e = query[i].second;
			u = edge[e].first,v = edge[e].second;
			merge(u,v,e);
		}
	}

	for (int i=1; i<=n; i++) {
		int gr = find(i);
		S[gr].insert(p[i]);
	}

	for (int i=1; i<=q; i++) {
		int qt = query[i].first;
		if (qt == 1) {
			v = query[i].second;
			handleQuery(v);
		}
		else {
			int k = query[i].second;
			handleSplit(k);
		}
	}

	return 0;
}

#include<bits/stdc++.h>
#define mz 1000000007
#define pii pair<int,int>
using namespace std;

int gg[400005][21];

int main()
{
	return 0;
}

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/priority_queue.hpp>
//#pragma GCC optimize("O3")
//#pragma GCC target("sse4")
//#pragma GCC target("avx2")

#define deb(x) cout << #x << " = " << x << "\n"
#define all(x) (x).begin(), (x).end()
#define len(x) (int) x.size()
#define lsb(x) (x) & -(x)
#define l(x) (x << 1) + 1
#define r(x) (x << 1) + 2
#define v(x) (int)(x - 'a')

#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define lb lower_bound
#define ub upper_bound

using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair <int, int> pii;
typedef pair <ld, ld> pld;
typedef pair <ll, ll> pll;

template <class T1, class T2 = less <T1>> using pb_heap = __gnu_pbds::priority_queue <T1, T2, binary_heap_tag>;
template <class T1, class T2 = null_type, class T3 = less <T1>> using pb_map = tree <T1, T2, T3, rb_tree_tag, tree_order_statistics_node_update>;
template <class T1, class T2 = null_type, class T3 = hash <T1>> using pb_umap = gp_hash_table <T1, T2, T3>;
template <class T1, class T2, class T3 = hash <T1>> using umap = unordered_map <T1, T2, T3>;
template <class T> using uset = unordered_set <T>;
template <class T> using vec = vector <T>;

const ll infll = numeric_limits <ll>::max() >> 1;
const int inf = numeric_limits <int>::max() >> 1;
const int N = 5e5 + 1;
int n, m, q, curr;
int arr[N];
int ind[N];

bool vis[N];

pii qry[N];
pii edge[N];

vec <int> roots;

struct Graph {
    int lef[N];
    int rig[N];
    vec <int> adj[N];
} graph;

struct Node {
    int l, r;
    pii mxm;
} node[N << 2];

struct Dsu {
    int par[N];
} dsu;

int root(int u) {
    return dsu.par[u] == u? u: dsu.par[u] = root(dsu.par[u]);
}

void unite(int u, int v) {
    u = root(u);
    v = root(v);
    int p = ++n;
    graph.adj[p].pb(u);
    graph.adj[p].pb(v);
    dsu.par[p] = p;
    dsu.par[u] = p;
    dsu.par[v] = p;
}

void merge(int id, int l, int r) {
    node[id].mxm = max(node[l].mxm, node[r].mxm);
}

void build(int id, int l, int r) {
    node[id].l = l;
    node[id].r = r;
    if(l == r) {
        node[id].mxm.xx = arr[ind[l]];
        node[id].mxm.yy = l;
        return;
    }
    int q = l + r >> 1;
    build(l(id), l, q);
    build(r(id), q + 1, r);
    merge(id, l(id), r(id));
}

void erase(int id, int i) {
    if(node[id].l == node[id].r) {
        node[id].mxm.xx = 0;
        return;
    }
    int q = node[id].l + node[id].r >> 1;
    if(i <= q) {
        erase(l(id), i);
    } else {
        erase(r(id), i);
    }
    merge(id, l(id), r(id));
}

pii query(int id, int l, int r) {
    if(node[id].l == l && node[id].r == r) {
        return node[id].mxm;
    }
    pii res = {0, 0};
    int q = node[id].l + node[id].r >> 1;
    if(l <= q) {
        res = max(res, query(l(id), l, min(q, r)));
    }
    if(r > q) {
        res = max(res, query(r(id), max(q + 1, l), r));
    }
    return res;
}

void dfs(int u) {
    static int t = 0;
    ind[++t] = u;
    graph.lef[u] = t;
    for(int v: graph.adj[u]) {
        dfs(v);
    }
    graph.rig[u] = t;
}

void input() {
    cin >> n >> m >> q;
    for(int i = 1; i <= n; ++i) {
        cin >> arr[i];
    }
    for(int i = 1; i <= m; ++i) {
        int u; cin >> u;
        int v; cin >> v;
        edge[i] = {u, v};
    }
    for(int i = 1; i <= q; ++i) {
        cin >> qry[i].xx;
        cin >> qry[i].yy;
        if(qry[i].xx == 2) {
            vis[qry[i].yy] = 1;
        }
    }
}

void solve() {
    for(int i = 1; i <= n; ++i) {
        dsu.par[i] = i;
    }
    for(int i = 1; i <= m; ++i) {
        if(!vis[i]) {
            int u = edge[i].xx;
            int v = edge[i].yy;
            unite(u, v);
        }
    }
    for(int i = q; i >= 1; --i) {
        if(qry[i].xx == 1) {
            roots.pb(root(qry[i].yy));
        } else {
            int u = edge[qry[i].yy].xx;
            int v = edge[qry[i].yy].yy;
            if(root(u) == root(v)) {
                continue;
            }
            unite(u, v);
        }
    }
    for(int i = 1; i <= n; ++i) {
        if(root(i) == i) {
            dfs(i);
        }
    }
    if(n > 100) {
        cout << "wtf\n";
        return;
    }
    build(0, 1, n);
    reverse(all(roots));
    for(int e: roots) {
        pii p = query(0, graph.lef[e], graph.rig[e]);
        erase(0, p.yy);
        cout << p.xx << "\n";
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    input();
    solve();
}

#include <bits/stdc++.h>
#define lc (id<<1)
#define rc (id<<1|1)
using namespace std;
typedef long long ll;
const int maxn = 5e5+10;
int p[maxn],a[maxn],b[maxn],flag[maxn];
int qur[maxn],id[maxn],f[maxn],tot;
int head[maxn],to[maxn<<1],nxt[maxn<<1],cnt,now;
void add(int u,int v){
    ++cnt,to[cnt] = v,nxt[cnt] = head[u],head[u] = cnt;
    ++cnt,to[cnt] = u,nxt[cnt] = head[v],head[v] = cnt;
}
int find(int x){
    return f[x]==x?x:f[x]=find(f[x]);
}

void unite(int x,int y){
    x = find(x);
    y = find(y);
    if(x==y) return ;
    ++tot;
    add(x,tot),add(y,tot);
    f[tot] = f[x] = f[y] = tot;
}
bool same(int x,int y){
    return find(x)==find(y);
}
int el[maxn],er[maxn],rk[maxn];
void dfs(int u,int pre){
    el[u] = ++now,rk[now] = u;
    for(int i=head[u];i;i=nxt[i]){
        int v = to[i];
        if(v==pre) continue;
        dfs(v,u);
    }
    er[u] = now;
}
int maxs[maxn<<2];
int Max(int i,int j){
    return p[rk[i]]>p[rk[j]]?i:j;
}
void push_up(int id){
    maxs[id] = 0;
    maxs[id] = Max(maxs[id<<1],maxs[id<<1|1]);
}
void build(int id,int l,int r){
    if(l==r){
        maxs[id] = l;
        return ;
    }
    int mid = (l+r)>>1;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
    push_up(id);
}

int query(int id,int l,int r,int x,int y){
    if(x<=l&&y>=r) return maxs[id];
    int mid = (l+r)>>1,ans = 0;
    if(x<=mid) ans = Max(ans,query(id<<1,l,mid,x,y));
    if(y>mid) ans = Max(ans,query(id<<1|1,mid+1,r,x,y));
    return ans;
}
void update(int id,int l,int r,int pos,int val){
    if(l==r){
        maxs[id] = val;
        return ;
    }
    int mid = (l+r)>>1;
    if(pos<=mid) update(id<<1,l,mid,pos,val);
    if(pos>mid) update(id<<1|1,mid+1,r,pos,val);
    push_up(id);
}
int main(){
    int n,m,q;
    scanf("%d%d%d",&n,&m,&q);
    tot = n,cnt = 0,now = 0;
    for(int i=1;i<=n+m;i++) f[i] = i;
    for(int i=1;i<=n;i++) scanf("%d",&p[i]);
    // printf("sss\n");
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a[i],&b[i]);
    }
    for(int i=1;i<=q;i++){
        scanf("%d%d",&qur[i],&id[i]);
        if(qur[i]==2) flag[id[i]] = true;
    }
    for(int i=1;i<=m;i++){
        if(!flag[i]) unite(a[i],b[i]);
    }
    for(int i=q;i>=1;i--){
        if(qur[i]==2){
            int x = id[i];
            if(same(a[x],b[x])) continue;
            unite(a[x],b[x]);
        }
    }
    for(int i=1;i<=tot;i++){
        if(f[i]==i) dfs(i,0);
    }
    build(1,1,now);
    for(int i=1;i<=q;i++){
        if(qur[i]==1){
            int root = find(id[i]);
            int ans = query(1,1,now,el[root],er[root]);
            printf("%d\n", p[rk[ans]]);
            update(1,1,now,ans,0);
        }
        else{
            int root = find(a[id[i]]);
            for(int i=head[root];i;i=nxt[i]){
                int v = to[i];
                f[v] = v;
            }
        }
    }
}

#include <bits/stdc++.h>
#define ls rt<<1
#define rs rt<<1|1
#define pb push_back
using namespace std;
typedef long long ll;
const int maxn = 7e5 + 5;
const int mod = 1e9 + 7;

int n,m,q;
int p[maxn],u[200010],v[200010],vis[300010],fa[maxn],op[500010][2],sz[maxn],boss[500010];
int pos[maxn],dfn[maxn],tot;
struct node {int w,pos;}t[maxn<<2];
vector<int>G[maxn];
int fid(int x){return x==fa[x]?x:fa[x]=fid(fa[x]); }

void dfs(int u) {
	pos[u]=++tot;
	dfn[tot]=u;
	sz[u]=1;
	for(int v:G[u]) dfs(v),sz[u]+=sz[v];
}

void push_up(int rt) {
	if(t[ls].w>t[rs].w) t[rt]=t[ls];
	else t[rt]=t[rs];
}
void build(int rt,int l,int r) {
	t[rt].w=t[rt].pos=0;
	if(l==r) {
		t[rt].w=p[dfn[l]];
		//cout<<l<<','<<t[rt].w<<','<<dfn[l]<<endl;
		t[rt].pos=l;
		return ;
	}
	int mid=l+r>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	push_up(rt);
}
void upd(int rt,int l,int r,int z) {
	if(l==r&&r==z) {
		t[rt].w=0;
		return ;
	}
	int mid=l+r>>1;
	if(z<=mid) upd(ls,l,mid,z);
	else upd(rs,mid+1,r,z);
	push_up(rt);
}
node ask(int rt,int l,int r,int ql,int qr)  {//cout<<ql<<','<<qr<<endl;
	if(ql<=l&&r<=qr) return t[rt];
	int mid=l+r>>1;
	node f1,f2;
	f1.w=f2.w=f1.pos=f2.pos=0;
	if(ql<=mid) f1=ask(ls,l,mid,ql,qr);
	if(qr>mid) f2=ask(rs,mid+1,r,ql,qr);
	if(f1.w>f2.w) return f1;
	else return f2;
}
int main() {
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++) {
    	scanf("%d",&p[i]);
    }
    for(int i=1;i<=m;i++) {
    	scanf("%d%d",&u[i],&v[i]);
    }
    for(int i=1;i<=q;i++) {
    	scanf("%d%d",&op[i][0],&op[i][1]);
    	if(op[i][0]==2) vis[op[i][1]]=1;
    }
    for(int i=1;i<=n+q;i++) fa[i]=i;
    for(int i=1;i<=m;i++) {
    	if(vis[i]) continue;
    	//cout<<i<<endl;
    	int fx=fid(u[i]),fy=fid(v[i]);
    	if(fx!=fy) {
    		n++;
			G[n].pb(fx);
			G[n].pb(fy);
			fa[fx]=n;
			fa[fy]=n;
    	}
    }

    //for(int i=1;i<=n;i++) cout<<fid(i)<<',';cout<<endl;
    for(int i=q;i>=1;i--) {
    	if(op[i][0]==2) {
    		int x=op[i][1];
    		int fx=fid(u[x]),fy=fid(v[x]);
    		if(fx!=fy) {
    			n++;
    			G[n].pb(fx);
    			G[n].pb(fy);
    			fa[fx]=n;
    			fa[fy]=n;
    			//cout<<i<<endl;
    		}

    	} else boss[i]=fid(op[i][1]);
    }
	//for(int i=1;i<=n;i++) cout<<fid(i)<<',';cout<<endl;return 0;
    for(int i=1;i<=n;i++) {
    	if(!dfn[pos[i]]) {
    		//cout<<i<<'_'<<fid(i)<<endl;
    		dfs(fid(i));
    	}
    }    //return 0;
    build(1,1,tot);
/*    cout<<tot<<',';
    for(int i=1;i<=tot;i++) printf("%d ",dfn[i]);
    printf("\n");*/

    for(int i=1;i<=q;i++) {
    	if(op[i][0]==1) {
    		node x=ask(1,1,tot,pos[boss[i]],pos[boss[i]]+sz[boss[i]]-1);
    		//
    		if(x.w>0) upd(1,1,tot,x.pos);
    		printf("%d\n",x.w);
    	}
    }
    return 0;
}

#include<bits/stdc++.h>

using namespace std;
typedef long long int lld;
#define rep(i,a,b) for(int i=a;i<b;i++)
#define trav(a,v) for(auto a:v)
int n,m,q;
int p[4000000];
vector<pair<int,int> >Q,E;
vector<int> tree[4000000];
bool used[4000000];
bool visited[4000000];
class DSU{
  int par[4000000];
  int sz[4000000];
  int Mx[4000000];
public:
  void init(){
    rep(i,0,3*n)par[i]=i,Mx[i]=i,sz[i]=1;
  }
  int root(int node){
    if(par[node]==node)return node;
    par[node]=root(par[node]);
    return par[node];
  }
  int Rep(int node){
    return Mx[root(node)];
  }
  void merge(int a, int b){
    a=root(a);
    b=root(b);
    if(a==b)return;
    if(sz[a]<sz[b])swap(a,b);
    par[b]=a;
    sz[a]+=sz[b];
    Mx[a]=max(Mx[a],Mx[b]);
  }
  bool same(int a, int b){
    a=root(a);
    b=root(b);
    if(a==b)return true;
    return false;
  }
};
DSU D;
int L[4000000];
int R[4000000];
int queries[4000000];
vector<int> ET;
void DFS(int node){
  if(visited[node])return;
  visited[node]=true;
  L[node]=ET.size();
  ET.push_back(node);
  trav(a,tree[node]){
    //cout<<node<<" "<<a<<endl;
    DFS(a);
  }
  R[node]=ET.size()-1;
}
class ST{
  pair<int,int> arr[4000000];
public:
  void build(int a, int b, int node){
    arr[node]={0,node};
    if(a==b)return;
    int mid=(a+b)/2;
    build(a,mid,2*node);
    build(mid+1,b,2*node+1);
  }
  void update(int a, int b, int node, int pos, int val){
    if(pos<a || b<pos)return;
    if(a==b){
      arr[node]={val,pos};
      return;
    }
    int mid=(a+b)/2;
    update(a,mid,2*node,pos,val);
    update(mid+1,b,2*node+1,pos,val);
    arr[node]=max(arr[2*node],arr[2*node+1]);
  }
  pair<int,int> query(int a, int b, int node, int x, int y){
    if(y<a || b<x)return {-1,-1};
    if(x<=a && b<=y)return arr[node];
    int mid=(a+b)/2;
    return max(query(a,mid,2*node,x,y),query(mid+1,b,2*node+1,x,y));
  }
};
ST S;
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);

  cin>>n>>m>>q;
  rep(i,0,n)cin>>p[i];
  rep(i,0,m){
    used[i]=false;
    int x,y;
    cin>>x>>y;
    x--;y--;
    E.push_back({x,y});
  }
  rep(i,0,q){
    int type;
    int idx;
    cin>>type>>idx;
    idx--;
    Q.push_back({type,idx});
    if(type==2)used[idx]=true;
  }
  D.init();
  int cnt=n;
  rep(i,0,m){
    if(!used[i]){
      //cout<<i<<endl;
      if(!D.same(E[i].first,E[i].second)){

	tree[cnt].push_back(D.Rep(E[i].first));
	D.merge(cnt,D.Rep(E[i].first));
	tree[cnt].push_back(D.Rep(E[i].second));
	D.merge(cnt,D.Rep(E[i].second));
	cnt++;
      }
    }
  }
  for(int i=q-1;i>-1;i--){
    if(Q[i].first==2){
      if(!D.same(E[Q[i].second].first,E[Q[i].second].second)){
	tree[cnt].push_back(D.Rep(E[Q[i].second].first));
	D.merge(cnt,D.Rep(E[Q[i].second].first));
	tree[cnt].push_back(D.Rep(E[Q[i].second].second));
	D.merge(cnt,D.Rep(E[Q[i].second].second));
	cnt++;
      }
    }else{
      queries[i]=D.Rep(Q[i].second);
    }
  }
  rep(i,0,cnt)visited[i]=false;
  for(int i=cnt-1;i>-1;i--){
    DFS(i);
  }
  //trav(a,ET)cout<<a<<endl;
  //rep(i,0,cnt)cout<<L[i]<<" "<<R[i]<<endl;
  S.build(0,cnt-1,1);
  rep(i,0,n){

    S.update(0,cnt-1,1,L[i],p[i]);
  }
  rep(i,0,q){
    if(Q[i].first==1){
      pair<int,int> in={L[queries[i]],R[queries[i]]};
      pair<int,int> ans=S.query(0,cnt-1,1,in.first,in.second);
      cout<<ans.first<<endl;
      S.update(0,cnt-1,1,ans.second,0);
    }
  }
  return 0;
}

#pragma region Macros
#pragma GCC optimize("O3")
#pragma GCC target("avx2,avx")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
#define ll long long
#define ld long double
#define rep2(i, a, b) for(ll i = a; i <= b; ++i)
#define rep(i, n) for(ll i = 0; i < n; ++i)
#define rep3(i, a, b) for(ll i = a; i >= b; --i)
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pb push_back
#define eb emplace_back
#define vi vector<int>
#define vll vector<ll>
#define vpi vector<pii>
#define vpll vector<pll>
#define overload2(_1, _2, name, ...) name
#define vec(type, name, ...) vector<type> name(__VA_ARGS__)
#define VEC(type, name, size)                                                                                \
    vector<type> name(size);                                                                                \
    IN(name)
#define vv(type, name, h, ...) vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define VV(type, name, h, w)                                                                                \
    vector<vector<type>> name(h, vector<type>(w));                                                                                \
    IN(name)
#define vvv(type, name, h, w, ...) vector<vector<vector<type>>> name(h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)                                                                                \
    vector<vector<vector<vector<type>>>> name(a, vector<vector<vector<type>>>(b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))
#define fi first
#define se second
#define all(c) begin(c), end(c)
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
using namespace std;
string YES[2] = {"NO", "YES"};
string Yes[2] = {"No", "Yes"};
string yes[2] = {"no", "yes"};
template <class T> using pq = priority_queue<T>;
template <class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
#define si(c) (int)(c).size()
#define INT(...)                                                                                \
    int __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define LL(...)                                                                                \
    ll __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define STR(...)                                                                                \
    string __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define CHR(...)                                                                                \
    char __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define DBL(...)                                                                                \
    double __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
int scan() { return getchar(); }
void scan(int &a) { cin >> a; }
void scan(long long &a) { cin >> a; }
void scan(char &a) { cin >> a; }
void scan(double &a) { cin >> a; }
void scan(string &a) { cin >> a; }
template <class T, class S> void scan(pair<T, S> &p) { scan(p.first), scan(p.second); }
template <class T> void scan(vector<T> &);
template <class T> void scan(vector<T> &a) {
    for(auto &i : a) scan(i);
}
template <class T> void scan(T &a) { cin >> a; }
void IN() {}
template <class Head, class... Tail> void IN(Head &head, Tail &... tail) {
    scan(head);
    IN(tail...);
}
template <class T, class S> inline bool chmax(T &a, S b) {
    if(a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T, class S> inline bool chmin(T &a, S b) {
    if(a > b) {
        a = b;
        return 1;
    }
    return 0;
}
vi iota(int n) {
    vi a(n);
    iota(all(a), 0);
    return a;
}
template <typename T> vi iota(vector<T> &a, bool greater = false) {
    vi res(a.size());
    iota(all(res), 0);
    sort(all(res), [&](int i, int j) {
        if(greater) return a[i] > a[j];
        return a[i] < a[j];
    });
    return res;
}
#define UNIQUE(x) sort(all(x)), x.erase(unique(all(x)), x.end())
vector<pll> factor(ll x) {
    vector<pll> ans;
    for(ll i = 2; i * i <= x; i++)
        if(x % i == 0) {
            ans.push_back({i, 1});
            while((x /= i) % i == 0) ans.back().second++;
        }
    if(x != 1) ans.push_back({x, 1});
    return ans;
}
template <class T> vector<T> divisor(T x) {
    vector<T> ans;
    for(T i = 1; i * i <= x; i++)
        if(x % i == 0) {
            ans.pb(i);
            if(i * i != x) ans.pb(x / i);
        }
    return ans;
}
template <typename T> void zip(vector<T> &x) {
    vector<T> y = x;
    sort(all(y));
    for(int i = 0; i < x.size(); ++i) { x[i] = lb(y, x[i]); }
}
int popcount(ll x) { return __builtin_popcountll(x); }
struct Setup_io {
    Setup_io() {
        ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
        cout << fixed << setprecision(15);
    }
} setup_io;
int in() {
    int x;
    cin >> x;
    return x;
}
ll lin() {
    unsigned long long x;
    cin >> x;
    return x;
}

template <typename T> struct edge {
    int from, to;
    T cost;
    int id;
    edge(int to, T cost) : from(-1), to(to), cost(cost) {}
    edge(int from, int to, T cost) : from(from), to(to), cost(cost) {}
    edge(int from, int to, T cost, int id) : from(from), to(to), cost(cost), id(id) {}
    edge &operator=(const int &x) {
        to = x;
        return *this;
    }
    operator int() const { return to; }
};
template <typename T> using Edges = vector<edge<T>>;

using Tree = vector<vector<int>>;
using Graph = vector<vector<int>>;
template <class T> using Wgraph = vector<vector<edge<T>>>;
Graph getG(int n, int m = -1, bool directed = false, int margin = 1) {
    Tree res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        cin >> a >> b;
        a -= margin, b -= margin;
        res[a].emplace_back(b);
        if(!directed) res[b].emplace_back(a);
    }
    return move(res);
}
template <class T> Wgraph<T> getWg(int n, int m = -1, bool directed = false, int margin = 1) {
    Wgraph<T> res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        T c;
        cin >> a >> b >> c;
        a -= margin, b -= margin;
        res[a].emplace_back(b, c);
        if(!directed) res[b].emplace_back(a, c);
    }
    return move(res);
}

#define i128 __int128_t
#define ull unsigned long long int
#define TEST                                                                                \
    INT(testcases);                                                                                \
    while(testcases--)
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    for(auto &e : v) cout << e << " ";
    cout << endl;
    return os;
}
template <class T, class S> ostream &operator<<(ostream &os, const pair<T, S> &p) {
    cout << "(" << p.fi << ", " << p.se << ")";
    return os;
}
template <class S, class T> string to_string(pair<S, T> p) { return "(" + to_string(p.first) + "," + to_string(p.second) + ")"; }
template <class A> string to_string(A v) {
    if(v.empty()) return "{}";
    string ret = "{";
    for(auto &x : v) ret += to_string(x) + ",";
    ret.back() = '}';
    return ret;
}

void dump() { cerr << endl; }
template <class Head, class... Tail> void dump(Head head, Tail... tail) {
    cerr << to_string(head) << " ";
    dump(tail...);
}
#define endl '\n'
#ifdef _LOCAL
#undef endl
#define debug(x)                                                                                \
    cout << #x << ": ";                                                                                \
    dump(x)
#else
#define debug(x)
#endif
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

// int rnd(int n) { return uniform_int_distribution<int>(0, n - 1)(rng); }
// ll rndll(ll n) { return uniform_int_distribution<ll>(0, n - 1)(rng); }

template <typename T> static constexpr T inf = numeric_limits<T>::max() / 2;
#pragma endregion

vector<int> a;
template <typename T = int> struct UnionFind {
    vector<int> data;
    vector<set<int>> s;
    struct A {
        int y, d;
        A() = default;
    };
    vector<A> hist;
    int num;

    UnionFind(int n) : num(n) {
        data.assign(n, -1);
        s.resize(n);
        rep(i, n) s[i].emplace(a[i]);
    }

    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if(x == y) {
            A a;
            a.y = -1;
            hist.eb(a);
            return false;
        }
        num--;
        if(data[x] > data[y]) swap(x, y);
        data[x] += data[y];
        A a;
        a.y = y, a.d = data[y];
        for(auto &e : s[y]) s[x].emplace(e);
        hist.eb(a);
        data[y] = x;
        return true;
    }

    int find(int x) {
        if(data[x] < 0) return x;
        return (data[x] = find(data[x]));
    }

    void undo() {
        auto &a = hist.back();
        hist.pop_back();
        if(a.y == -1) { return; }
        int y = a.y;
        int x = data[y];
        data[x] -= a.d;
        data[y] = a.d;
        for(auto it = s[y].begin(); it != s[y].end();) {
            auto it2 = s[x].find(*it);
            if(it2 != s[x].end())
                s[x].erase(it2), it++;
            else
                it = s[y].erase(it);
        }
    }
    int get(int x) {
        x = find(x);
        if(s[x].empty())
            return 0;
        else {
            int res = *s[x].rbegin();
            s[x].erase(--s[x].end());
            return res;
        }
    }
};

int main() {
    INT(n, m, q);
    a.resize(n);
    rep(i, n) cin >> a[i];
    vector<pii> E;
    rep(i, m) {
        INT(x, y);
        x--, y--;
        E.eb(x, y);
    }
    vi used(m);
    vi edges;
    vector<pii> query;
    rep(i, q) {
        INT(t, s);
        query.eb(t, --s);
        if(t == 2) {
            edges.eb(s);
            used[s] = true;
        }
    }
    rep(i, m) if(!used[i]) edges.eb(i);
    UnionFind uf(n);
    reverse(all(edges));
    for(auto i : edges) uf.unite(E[i].fi, E[i].se);
    for(auto [t, s] : query) {
        if(t == 1) {
            cout << uf.get(s) << endl;
        } else
            uf.undo();
    }
}

#include <bits/stdc++.h>
using namespace std;

int c[200005];
int indx[200005];

int a[300005];
int b[300005];

int op[500005];
int x[500005];

vector<int> AdjList[400005];

bool picked[300005];
int order[300005];

int p2[400005];

int n, m, q;
void init1(){
    for(int i = 1; i <= 2*n; i ++){
        p2[i] = i;
    }
}

int findSet(int i){
    return (p2[i] == i) ? i : (p2[i] = findSet(p2[i]));
}

bool isSameSet[300005];

// merge with new node of higher index than any of previous nodes
void unionSet(int u, int v){
    int x = findSet(u);
    int y = findSet(v);

    if(x == y){return;}
    if(x > y){swap(x, y);}
    p2[x] = y;
}

int p[400005][20];

int l[400005];
int r[400005];

int cnt = 0;
void dfs(int u){
    l[u] = cnt ++;
    for(int v: AdjList[u]){
        dfs(v);
    }
    r[u] = cnt;
}

int val[(1<<20)+5];
int f[400005];

void init(int i = 1, int s = 0, int e = 2*n){
    if(s == e){
        val[i] = f[s];
        return;
    }else{
        int l = (i<<1);
        int r = (i<<1)|1;
        int m = (s+e)>>1;
        init(l, s, m);
        init(r, m+1, e);
        val[i] = max(val[l], val[r]);
    }
}

int rmq(int x, int y, int i = 1, int s = 0, int e = 2*n){
    if(x <= s && e <= y){
        return val[i];
    }else{
        int l = (i<<1);
        int r = (i<<1)|1;
        int m = (s+e)>>1;

        if(x > m){
            return rmq(x, y, r, m+1, e);
        }else if(y <= m){
            return rmq(x, y, l, s, m);
        }else{
            return max(rmq(x, y, r, m+1, e), rmq(x, y, l, s, m));
        }
    }
}

void update(int p, int v, int i = 1, int s = 0, int e = 2*n){
    if(s == e){
        val[i] = v;
        return;
    }else{
        int l = (i<<1);
        int r = (i<<1)|1;
        int m = (s+e)>>1;

        if(p > m){
            update(p, v, r, m+1, e);
        }else if(p <= m){
            update(p, v, l, s, m);
        }
        val[i] = max(val[l], val[r]);
    }
}

int main(){
    scanf("%d%d%d", &n, &m, &q);

    for(int i = 1; i <= n; i ++){
        scanf("%d", &c[i]);
        indx[c[i]] = i;
    }

    memset(picked, false, sizeof(picked));
    for(int i = 1; i <= m; i ++){
        scanf("%d%d", &a[i], &b[i]);
    }

    int cnt = 0;
    for(int i = 1; i <= q; i ++){
        scanf("%d%d", &op[i], &x[i]);
        if(op[i] == 2){
            picked[x[i]] = true;
            order[cnt ++] = x[i];
        }
    }

    for(int i = 1; i <= m; i ++){
        if(!picked[i]){
            order[cnt ++] = i;
        }
    }

    assert(cnt == m);
    reverse(order, order+m);
    memset(p, -1, sizeof(p));
    int newNode = n+1;
    init1();
    for(int i = 0; i < m; i ++){
        int x = a[order[i]];
        int y = b[order[i]];
        //printf("merge %d and %d\n", x, y);

        int u = findSet(x);
        int v = findSet(y);

        isSameSet[i] = (u == v);
        if(u == v){continue;}

        unionSet(newNode, u);
        unionSet(newNode, v);

        p[u][0] = newNode;
        p[v][0] = newNode;

        //printf("edge: %d %d\n", newNode, u);
        //printf("edge: %d %d\n", newNode, v);
        AdjList[newNode].push_back(u);
        AdjList[newNode].push_back(v);

        newNode ++;
    }

    for(int k = 1; k <= 19; k ++){
        for(int i = 1; i <= 2*n; i ++){
            if(p[i][k-1] == -1){
                p[i][k] = -1;
            }else{
                p[i][k] = p[p[i][k-1]][k-1];
            }
        }
    }

    for(int i = 2*n; i >= 1; i --){
        if(p[i][0] == -1){
            //printf("source=%d\n", i);
            dfs(i);
        }
    }

    memset(f, 0, sizeof(f));
    for(int i = 1; i <= n; i ++){
        f[l[i]] = c[i];
        //printf("l[%d] = %d\n", i, l[i]);
        //printf("f[%d]=%d\n", l[i], c[i]);
    }
    init();

    int curNode = newNode;
    //printf("newNode: %d\n", newNode);

    int curIndx = m-1;
    for(int i = 1; i <= q; i ++){
        if(op[i] == 1){
            int y = x[i];
            for(int k = 19; k >= 0; k --){
                if(p[y][k] == -1){continue;}
                if(p[y][k] < curNode){
                    y = p[y][k];
                }
            }
            /*printf("debug: %d %d %d\n", l[y], r[y], 22323123);
            for(int i = 0; i < 2*n; i ++){
                printf("%d ", rmq(i, i));
            }
            printf("\n");*/
            int ans = rmq(l[y], r[y]);
            if(ans != 0){
                update(l[indx[ans]], 0);
            }
            printf("%d\n", ans);
        }else{
            if(!isSameSet[curIndx]){
                curNode --;
            }
            //printf("curNode=%d\n", curNode);
            curIndx --;
        }
    }

    return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(auto i = (a); i < (b); i++)
#define pb push_back
#define fs first
#define sc second
typedef long long ll;
typedef pair<int,int> ii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ii> vii;
typedef vector<vii> vvii;

const double EPS = 1e-9;

typedef pair<int,ii> T;

set<ii> BST[200'050];
struct union_find {
	vi p;
    vi sz;
    vi A;

    vector<set<int>> BACK;

	union_find(int n, vi &b) : A(b), p(n), sz(n,1), BACK(n,set<int>()) {
        rep(i,0,n) p[i] = i;
        rep(i,0,n) BST[i].insert(ii(A[i],i));
    }

    stack<T> q;
    int cur = 0;

	int find(int a) {
        if(a == p[a]) return a;
        return find(p[a]);
    }

    int best(int a) {
        a = find(a);
        if(BST[a].size() == 0) return 0;
        ii val = *(--BST[a].end());
        BST[a].erase(val);
        A[val.sc] = 0;
        return val.fs;
    }

	bool joined(int a, int b) {
        return find(a) == find(b);
    }

    void change(int at, int from, int to) {
        BST[from].erase(ii(A[at],at));
        BST[to].insert(ii(A[at],at));
        for(auto a : BACK[at]) {
            change(a, from, to);
        }
    }

	void unite(int a, int b) {

        a = find(a);
        b = find(b);
        if(a == b) {
            q.push(T(-1,ii(0,0)));
            return;

        }

        if(sz[find(a)] < sz[find(b)]) {
            // go through smaller size remove and add to other
            change(a, a, b);

            sz[find(b)] += sz[find(a)];

            q.push( T(cur, ii(a, p[a])) );
            BACK[b].insert(find(a));

            p[find(a)] = find(b);

        } else {
            change(b, b, a);

            sz[find(a)] += sz[find(b)];
            q.push( T(cur, ii(b, p[b])) );

            BACK[a].insert(find(b));

            p[find(b)] = find(a);

        }
    }

    void pop() {
        T a = q.top();
        q.pop();
        if(a.fs == -1) return;
        change(a.sc.fs, find(a.sc.fs), a.sc.fs);
        BACK[find(a.sc.fs)].erase(a.sc.fs);
        sz[find(a.sc.fs)] -= sz[a.sc.fs];
        p[a.sc.fs] = a.sc.sc;
    }
};

int main() {
    cin.sync_with_stdio(false);
    int n,m,q;
    cin >> n >> m >> q;

    vi A(n);
    rep(i,0,n) cin >> A[i];
    vii E;
    rep(i,0,m) {
        int u,v;
        cin >> u >> v;
        u--;v--;
        E.pb(ii(u,v));
    }
    union_find un(n, A);

    vii OP(q);
    rep(i,0,q) cin >> OP[i].fs >> OP[i].sc;
    for(int i = q-1; i >= 0; i--) {
        if(OP[i].fs == 2) {
            un.unite(E[OP[i].sc-1].sc, E[OP[i].sc-1].fs);
        }
    }
    for(int i = 0; i < q; i++) {
        if(OP[i].fs == 1) {
            int val = un.best(OP[i].sc-1);
            cout << val << endl;
        } else {
            un.pop();
        }
    }
}

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
#define rl register long long
#define N 300010
ll pi[N],cnt,fa[N],n,m,q,hd[N],t[N<<1],nxt[N<<1],lnm[N<<1],rnm[N<<1],dcnt,adfn[N];
inline void add_edge(rl u,rl v){nxt[++cnt]=hd[u],t[cnt]=v,hd[u]=cnt;}
inline ll ffa(rl x){return fa[x]==x?x:fa[x]=ffa(fa[x]);}
struct qry{
	ll tp,v,prt;
}qrys[N<<2];
struct edge{ll u,v;bool dll;}es[N<<1];
inline ll mmin(rl a,rl b){return a<b?a:b;}
inline ll mmax(rl a,rl b){return a>b?a:b;}
struct ST{
	ll mxi[N<<2];
	inline void pushup(rl u){mxi[u]=mmax(mxi[u<<1],mxi[u<<1|1]);}
	void build(rl cl,rl cr,rl u){if(cl==cr){mxi[u]=pi[adfn[cl]];return;}rl mid=(cl+cr)>>1;build(cl,mid,u<<1),build(mid+1,cr,u<<1|1);pushup(u);}
	ll query(rl ql,rl qr,rl cl,rl cr,rl u){
		if(cl>qr || cr<ql) return 0LL;
		if(ql<=cl && qr>=cr) return mxi[u];
		rl mid=(cl+cr)>>1;return mmax(query(ql,qr,cl,mid,u<<1),query(ql,qr,mid+1,cr,u<<1|1));
	}
	void del(rl ql,rl qr,rl cl,rl cr,rl u,rl p){
		// printf("del: %lld %lld %lld\n", cl,cr,u);
		if(cl>qr || cr<ql) return;
		if(ql<=cl && qr>=cr){if(mxi[u]==p) del2(u,p,cl,cr);return;}
		rl mid=(cl+cr)>>1;del(ql,qr,cl,mid,u<<1,p),del(ql,qr,mid+1,cr,u<<1|1,p);
		pushup(u);
	}
	void del2(rl u,rl p,rl cl,rl cr){
		// printf("%lld %lld\n",cl,u );
		rl mid=(cl+cr)>>1;if(cl==cr){mxi[u]=0;return;}
		mxi[u<<1]==p?del2(u<<1,p,cl,mid):del2(u<<1|1,p,mid+1,cr);
		pushup(u);
	}
}T;
void dfs(rl u){
	if(!hd[u]){adfn[++dcnt]=u;lnm[u]=rnm[u]=dcnt;return;}
	lnm[u]=2e17;
	for(rl p=hd[u];p;p=nxt[p])
		dfs(t[p]),lnm[u]=mmin(lnm[u],lnm[t[p]]),rnm[u]=mmax(rnm[u],rnm[t[p]]);
}
int main(){
	scanf("%lld %lld %lld",&n,&m,&q);
	for(rl i=1;i<=n;++i)
		scanf("%lld",&pi[i]);
	for(rl i=1;i<=m;++i)
		scanf("%lld %lld",&es[i].u,&es[i].v),es[i].dll=false;
	for(rl i=0;i<q;++i)
		scanf("%lld %lld",&qrys[i].tp,&qrys[i].v),qrys[i].tp==2?es[qrys[i].v].dll=true:0LL;
	for(rl i=1;i<=m;++i) if(!es[i].dll)
		qrys[q++]=(qry){2LL,i,0LL};
	for(rl i=1;i<=n;++i)
		fa[i]=i;
	for(rl i=q-1;i>=0;--i){
		if(qrys[i].tp==2){
			if(ffa(es[qrys[i].v].u)==ffa(es[qrys[i].v].v)) continue;
			++n;
			add_edge(n,ffa(es[qrys[i].v].u)),add_edge(n,ffa(es[qrys[i].v].v));
			fa[ffa(es[qrys[i].v].u)]=fa[ffa(es[qrys[i].v].v)]=fa[n]=n;
		}else qrys[i].prt=ffa(qrys[i].v);
	}
	for(rl i=1;i<=n;++i) if(ffa(i)!=ffa(1)){
		++n;
		add_edge(n,ffa(i)),add_edge(n,ffa(1));
		fa[ffa(i)]=fa[ffa(1)]=fa[n]=n;
	}
	dfs(n);
	T.build(1,n,1);
	// for(rl i=1;i<=dcnt;++i)
		// printf("%lld\n", adfn[i]);
	for(rl i=0,j;i<q;++i) if(qrys[i].tp==1){
		// printf("%lld %lld\n", lnm[qrys[i].prt],rnm[qrys[i].prt]);
		j=T.query(lnm[qrys[i].prt],rnm[qrys[i].prt],1,n,1);
		printf("%lld\n", j);T.del(lnm[qrys[i].prt],rnm[qrys[i].prt],1,n,1,j);
	}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
template<class T> using oset=tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define sz(v) (int)v.size()
#define ar array
// #define f first
// #define s second
typedef vector<int> vi;
typedef long long ll;
typedef long double ld;
const int MAXN = 2e5+10, MAXM = 3e5+10, MAXQ = 5e5+10, MAXL = 20, ALP = 26, MOD = 1e9+7, MAXK = 810;
const string  no = "NO\n", yes = "YES\n";
const int hA[4] = {1, 0, -1, 0}, kA[4] = {0, 1, 0, -1};
const ll INF = 9e18+10;

int n, m, q, a[MAXN], p[MAXN], sz[MAXN], split[MAXN], loc[MAXN], amt=0;
set<ar<int, 2>> ans[MAXN];
vector<int> ch[MAXN];
ar<int, 2> ed[MAXM], qs[MAXQ+MAXM];
bool del[MAXN], used[MAXM];

int find_set(int v){
    for (; v != p[v]; v = p[v], amt++);
    return v;
}
int f_find_set(int v){ return v==p[v]?v:p[v]=find_set(p[v]); }
int union_sets(int a, int b){
    // cout << a << ' ' << b << "\n";
    if ((a=find_set(a))==(b=find_set(b))) return -1;
    if (sz[a] < sz[b]) swap(a, b);
    p[b] = a, sz[a] += sz[b]; sz[b]=0;
    return b;
}
void er(set<ar<int, 2>>& s, ar<int, 2> c){
    s.erase(c);
}
void dfs(int c, int os, int ns){
    if (!del[c]) er(ans[os], ar<int, 2>{a[c], c}), ans[ns].insert(ar<int, 2>{a[c], c});
    loc[c] = ns;
    for (auto nxt : ch[c]) dfs(nxt, os, ns);
}

void fsc(int &x){
    register int c;
    x = 0; c=getchar();
    for(;(c>47 && c<58);c=getchar())
        x = (x<<1) + (x<<3) +c -48;
}
void solve(){
    fsc(n), fsc(m), fsc(q);
    for (int i = 0; i < n; i++) fsc(a[i]);
    for (int i = 0; i < m; i++) fsc(ed[i][0]), fsc(ed[i][1]), ed[i][0]--, ed[i][1]--;
    memset(used, 0, sizeof(used));
    for (int i = 0; i < q; i++){
        ar<int, 2> c; fsc(c[0]), fsc(c[1]), --c[1];
        qs[i]=c; if (c[0] == 2) used[c[1]]=1;
    }
    for (int i = 0; i < m; i++) if (!used[i]) qs[q] = ar<int, 2>{2, i}, q++;
    //each unite operation corresponds to a vertex
    //query -> query operation for a subtree
    //multiset -> small to large splitting?
    iota(p, p+n, 0); fill(sz, sz+n, 1); memset(split, -1, sizeof(split));
    for (int i = q-1; i >= 0; i--) if (qs[i][0] == 2) split[i] = union_sets(ed[qs[i][1]][0], ed[qs[i][1]][1]);//, cout << ed[qs[i][1]][0] << ' ' << ed[qs[i][1]][1] << ' ' << split[i] << '\n';
    for (int i = 0; i < n; i++) {
        if (p[i] != i) ch[p[i]].push_back(i);
    }
    for (int i = 0; i < n; i++){
        loc[i] = f_find_set(i); ans[loc[i]].insert({a[i], i});
    }
    for (int i = 0; i < q; i++){
        auto c = qs[i];
        if (c[0] == 1){
            auto& cur = ans[loc[c[1]]];
            if (cur.empty()){ cout << 0 <<  '\n'; continue; }
            auto cans=*cur.rbegin(); del[cans[1]]=1;
            printf("%d\n", cans[0]); er(cur, cans);
        } else {
            int v = split[i];
            if (v == -1) continue;
            dfs(v, loc[v], v);

        }
    }
}
int main(){
    ios::sync_with_stdio(false); cin.tie(0);
    int t=1;
    // cin >> t;
    while (t--) solve();
}

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
using namespace std;
const int maxn = 2e5+10;
const int maxm = 3e5+10;
const int maxq = 5e5+10;

int read(){
	int x=0,f=1;
	char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<3)+(x<<1)+c-48;c=getchar();}
	return x*f;
}

int k,m,n,q;
int T[maxn<<1],p[maxn<<1],fa[maxn<<1],ch[maxn<<1][2],tot=0;
int L[maxn<<1],R[maxn<<1],a[maxn],tim=0,Fa[maxn<<1][18];
struct node{
	int x,y;
}E[maxm];
int vis[maxm];
pair<int,int> P[maxq];
int find(int x){if(x==fa[x])return x;return fa[x]=find(fa[x]);}
void dfs(int x){
	L[x]=tim+1;
	for(int i=1;i<=17;i++)Fa[x][i]=Fa[Fa[x][i-1]][i-1];
	if(x<=n)a[++tim]=p[x];
	if(ch[x][0])dfs(ch[x][0]);
	if(ch[x][1])dfs(ch[x][1]);
	R[x]=tim;
}
int max_[maxn<<2];
void build(int k,int l,int r){
	if(l==r){max_[k]=a[l];return;}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	max_[k]=max(max_[k<<1],max_[k<<1|1]);
}
int query(int k,int l,int r,int ls,int rs){
	if(ls<=l && r<=rs)return max_[k];
	int mid=(l+r)>>1,ans=0;
	if(mid>=ls)ans=query(k<<1,l,mid,ls,rs);
	if(mid+1<=rs)ans=max(query(k<<1|1,mid+1,r,ls,rs),ans);
	return ans;
}

void modify(int k,int l,int r,int v){
	if(l==r){max_[k]=0;return;}
	int mid=(l+r)>>1;
	if(max_[k<<1]==v)modify(k<<1,l,mid,v);
	else modify(k<<1|1,mid+1,r,v);
	max_[k]=max(max_[k<<1],max_[k<<1|1]);
}

int main(){
	n=read();m=read();q=read();
	for(int i=1;i<=n;i++)p[i]=read();
	for(int i=1;i<=m;i++){
		E[i].x=read();E[i].y=read();
	}
	for(int i=1;i<=q;i++){
		P[i].first=read();P[i].second=read();
		if(P[i].first==2)vis[P[i].second]=1;
	}
	for(int i=1;i<=n;i++){fa[i]=i;T[i]=q+1;}tot=n;
	for(int i=1;i<=m;i++){
		if(vis[i])continue;
		int X=find(E[i].x),Y=find(E[i].y);
		if(X!=Y){
			tot++;
			T[tot]=q+1;
			Fa[X][0]=Fa[Y][0]=fa[X]=fa[Y]=fa[tot]=tot;
			ch[tot][0]=X;ch[tot][1]=Y;
		}
	}
	for(int i=q;i>=1;i--){
		if(P[i].first==2){
			int X=find(E[P[i].second].x),Y=find(E[P[i].second].y);
			if(X!=Y){
				tot++;
				T[tot]=i;
				Fa[X][0]=Fa[Y][0]=fa[X]=fa[Y]=fa[tot]=tot;
				ch[tot][0]=X;ch[tot][1]=Y;
			}
		}
	}
	for(int i=1;i<=tot;i++)if(fa[i]==i)dfs(i);
	build(1,1,n);
	for(int i=1;i<=q;i++){
		if(P[i].first==1){
			int x=P[i].second;
			for(int j=17;j>=0;j--)if(T[Fa[x][j]]>i)x=Fa[x][j];
			int ans=query(1,1,n,L[x],R[x]);
			printf("%d\n",ans);
			modify(1,1,n,ans);
		}
	}
	return 0;
}

#include <bits/stdc++.h>
#define DEBUG if(0)
#define lli long long int
#define ldouble long double
using namespace std;

const int maxN = 2e5, maxNE = 5e5, maxE = 3e5, maxQ = 5e5; int n, m, q;
const int inf = maxNE + 1;

int p[maxN];
struct Edge
{
  int u, v, done;
  void read() { scanf("%d %d", &u, &v), done = false; u--, v--; }
};
Edge edges[maxE];

struct Query
{
  int type, value, artificial, queryRoot;
  void read() { scanf("%d %d", &type, &value); value--; }
};
Query queries[maxQ];

int parent[maxNE];
int root(int u)
{
  return parent[u] < 0 ? u : parent[u] = root(parent[u]);
}
vector<int> tree[maxNE];
void merge(int u, int v)
{
  if ((u = root(u)) == (v = root(v))) return;
  // if (parent[u] > parent[v]) swap(u, v);
  parent[u] += parent[v];
  parent[v] = u;
  tree[u].push_back(v), tree[v].push_back(u);
}

void printNode(int u)
{
  printf("%c%d", u < n ? 'v' : 'q', u);
  if (u < n) printf("-%d", p[u]);
}
void printTree(int u = 0, int prv = -1, int depth = 0)
{
  for (int i = 0; i < depth; i++) printf("   ");
  printNode(u); printf("\n");
  for (int v: tree[u])
    if (v != prv)
      printTree(v, u, depth + 1);
}

bool visited[maxNE];
vector<int> roots;
void visit(int u)
{
  if (visited[u]) return;
  visited[u] = true;
  for (int v: tree[u]) visit(v);
}

vector<vector<int>> eulerTours;
int myEulerTour[maxNE], in[maxNE], out[maxNE];
void buildEulerTour(int u, int prv = -1)
{
  myEulerTour[u] = eulerTours.size() - 1;
  in[u] = eulerTours.back().size();
  eulerTours.back().push_back(u);
  for (int v: tree[u])
    if (v != prv)
      buildEulerTour(v, u);
  out[u] = eulerTours.back().size();
  eulerTours.back().push_back(u);
}

struct MaxData
{
  int value, vertex;
  MaxData operator+(const MaxData &other)
  {
    if (value > other.value)
      return *this;
    return other;
  }
};
const MaxData maxNil = MaxData{-1, -1};

template<class T>
struct Segtree
{
  int size;
  T nil;
  vector<T> data;
  vector<T> st;
  Segtree() { }
  Segtree(int size, T nil) : size(size), nil(nil)
  {
    data.resize(size);
    st.resize(4*size);
  }
  Segtree(vector<T> &data, T nil) : size(data.size()), data(data), nil(nil)
  {
    st.resize(4*size);
    build();
  }
  void build() { build(1, 0, size - 1); }
  T query(int qlo, int qhi) { return query(qlo, qhi, 1, 0, size - 1); }
  void update(int pos, T value) { update(pos, value, 1, 0, size - 1); }
  void build(int i, int lo, int hi)
  {
    if (lo == hi)
    {
      st[i] = data[lo];
      return;
    }
    int mid = (lo + hi) >> 1;
    build(2*i, lo, mid), build(2*i + 1, mid + 1, hi);
    st[i] = st[2*i] + st[2*i + 1];
  }
  T query(int qlo, int qhi, int i, int lo, int hi)
  {
    if (hi < qlo || lo > qhi) return nil;
    if (lo >= qlo && hi <= qhi) return st[i];
    int mid = (lo + hi) >> 1;
    return query(qlo, qhi, 2*i, lo, mid) + query(qlo, qhi, 2*i + 1, mid + 1, hi);
  }
  void update(int pos, T &value, int i, int lo, int hi)
  {
    if (lo == hi)
    {
      st[i] = data[lo] = value;
      return;
    }
    int mid = (lo + hi) >> 1;
    if (pos <= mid) update(pos, value, 2*i, lo, mid);
    else update(pos, value, 2*i + 1, mid + 1, hi);
    st[i] = st[2*i] + st[2*i + 1];
  }
};
vector<Segtree<MaxData>> psegs;

int main()
{
  while (scanf("%d %d %d", &n, &m, &q) != EOF)
  {
    memset(parent, -1, sizeof(parent));
    for (int i = 0; i < maxNE; i++) tree[i].clear();

    for (int i = 0; i < n; i++)
      scanf("%d", &p[i]);
    for (int i = 0; i < m; i++)
      edges[i].read();

    for (int i = 0; i < q; i++)
    {
      queries[i].read();
      if (queries[i].type == 2)
        edges[queries[i].value].done = true;
    }

    int artificials = n;
    for (int i = 0; i < m; i++)
      if (!edges[i].done)
      {
        Edge &e = edges[i];
        if (root(e.u) == root(e.v)) continue;
        merge(artificials, e.u), merge(artificials, e.v);
        artificials++;
      }

    for (int i = q - 1; i >= 0; i--)
      if (queries[i].type == 2)
      {
        Edge &e = edges[queries[i].value];
        if (root(e.u) == root(e.v)) continue;
        merge(artificials, e.u), merge(artificials, e.v);
        artificials++;
      }
      else
        queries[i].queryRoot = root(queries[i].value);

    memset(visited, false, sizeof(visited));
    roots.clear();
    for (int i = artificials - 1; i >= 0; i--)
      if (!visited[i])
      {
        visit(i);
        roots.push_back(i);
      }

    eulerTours.clear(), psegs.clear();
    for (int i = 0; i < roots.size(); i++)
    {
      eulerTours.push_back(vector<int>());
      buildEulerTour(roots[i]);
      psegs.push_back(Segtree<MaxData>(eulerTours.back().size(), maxNil));
      for (int j = 0; j < eulerTours.back().size(); j++)
      {
        int u = eulerTours.back()[j];
        psegs.back().data[j].value = u < n ? p[u] : -1;
        psegs.back().data[j].vertex = u < n ? u : -1;
      }
      psegs.back().build();
    }

    DEBUG
    {
      for (int i = 0; i < roots.size(); i++)
      {
        printTree(roots[i]);
        printf("--------\n");
      }
      for (int i = 0; i < eulerTours.size(); i++)
      {
        for (int u: eulerTours[i])
        {
          printNode(u);
          printf(" ");
        }
        printf("\n-----\n");
      }
    }

    for (int i = 0; i < q; i++)
      if (queries[i].type == 1)
      {
        int u = queries[i].value, met = myEulerTour[u];
        DEBUG printf("\tquery %d %d >= %d\n", u + 1, met, i + 1);

        int highestQuery = queries[i].queryRoot;
        int lo = in[highestQuery], hi = out[highestQuery];
        DEBUG printf("\t\thighestQuery: %d\n", highestQuery);

        MaxData ans = psegs[met].query(lo, hi);
        printf("%d\n", ans.value);

        psegs[met].update(in[ans.vertex], maxNil);
        psegs[met].update(out[ans.vertex], maxNil);
      }
  }
  return 0;
}

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 5e5+5;

int A[N];
int del_edges[N];
pair<int,int> E[N];
vector<pair<int,int>> queries;

vector<int> fu_set[N];
set<pair<int, int>> R_set[N];
vector<pair<pair<int, int>, int>> mem_op;
int oj[N];

void un(int a, int b, bool mem, int num)
{
	if(oj[a] != oj[b])
	{
		int x = oj[a];
		int y = oj[b];
		if(fu_set[x].size() < fu_set[y].size()) swap(x, y);
		while(!fu_set[y].empty())
		{
			oj[fu_set[y].back()] = x;
			fu_set[x].push_back(fu_set[y].back());
		       	fu_set[y].pop_back();

			if(mem) mem_op.push_back({{x, y}, num});
		}
	}
}

int main()
{
	int n, m, q;
	scanf("%d%d%d",&n,&m,&q);

	for(int i=1;i<=n;i++)
	{
		scanf("%d",&A[i]);
	}

	for(int i=1;i<=m;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		E[i] = make_pair(a,b);
		del_edges[i] = false;
	}

	for(int i=1;i<=q;i++)
	{
		int r, x;
		scanf("%d%d",&r,&x);
		queries.emplace_back(r,x);
		if(r==2) del_edges[x] = true;
	}

	for(int i=1;i<=n;i++)
	{
		oj[i] = i;
		fu_set[i].push_back(i);
	}

	for(int i=1;i<=m;i++)
	{
		if(!del_edges[i]) un(E[i].first, E[i].second, false, i);
	}

	for(int i=int(queries.size())-1;i>=0;i--)
	{
		if(queries[i].first==2) un(E[i].first, E[i].second, true, i);
	}

	for(int i=1;i<=n;i++)
	{
		for(auto z : fu_set[i])
		{
			R_set[i].insert(make_pair(A[z], z));
		}
	}

	for(int i=0;i<int(queries.size());i++)
	{
		if(queries[i].first == 1)
		{
			int x = oj[queries[i].second];
			auto it = R_set[x].end();
			it--;
			int id = it->second;
			R_set[x].erase(it);
			printf("%d\n", A[id]);
			A[id] = 0;
			R_set[x].insert(make_pair(0, id));
		}

		else
		{
			while(!mem_op.empty() && mem_op.back().second == i)
			{
				int y = mem_op.back().first.first;
				int x = mem_op.back().first.second;

				int id = fu_set[y].back();
				R_set[y].erase(R_set[y].find(make_pair(A[id], id)));
				R_set[x].insert(make_pair(A[id], id));

				oj[fu_set[y].back()] = x;
				fu_set[x].push_back(fu_set[y].back());
		       		fu_set[y].pop_back();
				mem_op.pop_back();
			}
		}
	}
}

#include <bits/stdc++.h>
#define DIM 800010
using namespace std;

vector <int> L[DIM],w[DIM];
pair <int,int> poz[DIM],mch[DIM];
int aint[DIM*4],sol[DIM],v[DIM],E[DIM],t[DIM],g[DIM],f[DIM];
struct query{
    int tip,val;
} qry[DIM];

int n,m,q,i,j,x,y,k,el;

int get_rad (int x){
    int nr = x;
    while (t[x] > 0)
        x = t[x];

    while (t[nr] > 0){
        int aux = t[nr];
        t[nr] = x;
        nr = aux;
    }

    return x;
}

void uneste (int x, int y){
    int radx = get_rad (x), rady = get_rad (y);
    if (radx != rady){
        n++;
        L[n].push_back(radx);
        L[n].push_back(rady);

        t[n] += t[radx] + t[rady];
        t[radx] = n, t[rady] = n;
    }
}

void update (int nod, int st, int dr, int poz, int val){
    if (st == dr){
        aint[nod] = val;
        return;
    }
    int mid = (st+dr)>>1;
    if (poz <= mid)
        update (nod<<1,st,mid,poz,val);
    else update ((nod<<1)|1,mid+1,dr,poz,val);

    if (v[aint[nod<<1]] > v[aint[(nod<<1)|1]])
        aint[nod] = aint[nod<<1];
    else aint[nod] = aint[(nod<<1)|1];
}

int query (int nod, int st, int dr, int x, int y){
    int soll = n+1;
    if (x <= st && dr <= y)
        return aint[nod];

    int mid = (st+dr)>>1;
    if (x <= mid){
        int val = query (nod<<1,st,mid,x,y);
        if (v[val] > v[soll])
            soll = val;
    }
    if (y > mid){
        int val = query ((nod<<1)|1,mid+1,dr,x,y);
        if (v[val] > v[soll])
            soll = val;
    }
    return soll;
}
void dfs (int nod, int tata){
    E[++k] = nod;
    poz[nod].first = k;

    update (1,1,n,poz[nod].first,nod);

    for (auto vecin : L[nod])
        if (vecin != tata)
            dfs (vecin,nod);
    poz[nod].second = k;
}
void dfs2 (int nod, int tata){

    for (int i=w[nod].size()-1;i>=0;i--){
        int pos = query (1,1,n,poz[nod].first,poz[nod].second);
        sol[el - w[nod][i] + 1] = v[pos];
        v[pos] = 0;
        update (1,1,n,poz[nod].first,pos);
    }

    for (auto vecin : L[nod])
        if (vecin != tata)
            dfs2 (vecin,nod);

}

int main (){

    //FILE *fin = fopen ("date.in","r");
    //FILE *fout = fopen ("date.out","w");

    FILE *fin = stdin;
    FILE *fout = stdout;

    fscanf (fin,"%d%d%d",&n,&m,&q);

    for (i=1;i<=n;i++)
        fscanf (fin,"%d",&v[i]);

    for (i=1;i<=m;i++)
        fscanf (fin,"%d%d",&mch[i].first,&mch[i].second);

    for (i=1;i<=q;i++){
        fscanf (fin,"%d%d",&qry[i].tip,&qry[i].val);
        if (qry[i].tip == 2)
            f[qry[i].val] = 1;
    }

    memset (t,-1,sizeof t);

    /// mai adaug eu query uri pana am toate muchiile sterse
    for (i=1;i<=m;i++)
        if (!f[i]){
            int radx = get_rad (mch[i].first), rady = get_rad (mch[i].second);
            if (radx != rady){
                if (t[radx] > t[rady])
                    swap (radx,rady);
                t[radx] += t[rady];
                t[rady] = radx;
                L[radx].push_back(rady);
            }
        }

    for (i=q;i;i--){
        if (qry[i].tip == 1){
            int rad = get_rad (qry[i].val);
            w[rad].push_back(++el);
        } else {
            int idx = qry[i].val;
            uneste (mch[idx].first,mch[idx].second);
        }
    }

    for (i=1;i<=n;i++)
        if (t[i] < 0)
            dfs (i,0);

    for (i=1;i<=n;i++)
        if (t[i] < 0)
            dfs2 (i,0);

    for (i=1;i<=el;i++)
        fprintf(fout,"%d\n",sol[i]);

    return 0;
}

/**
 *    author:  otera
**/
#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<deque>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
using namespace std;

#define int long long
typedef long long ll;
typedef unsigned long long ul;
typedef unsigned int ui;
typedef long double ld;
const int inf=1e9+7;
const ll INF=1LL<<60 ;
const ll mod=1e9+7 ;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef complex<ld> Point;
const ld eps = 1e-8;
const ld pi = acos(-1.0);
typedef pair<int, int> P;
typedef pair<ld, ld> LDP;
typedef pair<ll, ll> LP;
#define fr first
#define sc second
#define all(c) c.begin(),c.end()
#define pb push_back
#define debug(x)  cerr << #x << " = " << (x) << endl;
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }

int n, m, q;
vector<int> p;
vector<pair<int, int>> es;

struct UnionFind {
    int n;
    vector<int> par;
    vector<set<int>> nums;
    vector<vector<int>> add;
    vector<pair<int, set<int>>> addp;
    vector<bool> ers;

    UnionFind(int n_) : n(n_), par(n_, -1), nums(n_, set<int>()), ers(n_ + 1, false){
        rep(i, n_) {
            nums[i].insert(p[i]);
        }
    }

    int root(int x) {
        if(par[x] < 0) return x;
        return root(par[x]);
    }

    void pop() {
        if(add.size()) {
            auto ad = add.back();
            add.pop_back();
            auto adp = addp.back();
            addp.pop_back();
            par[ad[0]] = ad[1], par[ad[2]] = ad[3];
            for(int z: adp.sc) {
                if(n == 96) cout << ad[0] << " " << ad[2] << " " << z << endl;
                if(ers[z]) {
                    if(n == 96) cout << "ers" << z << endl;
                    nums[ad[2]].erase(z);
                }
                nums[ad[0]].erase(z);
            }
        }
    }

    bool merge(int x, int y) {
        x = root(x), y = root(y);
        if(x == y) return false;
        if(par[x] > par[y]) swap(x, y);
        add.push_back({x, par[x], y, par[y]});
        set<int> adp;
        for(int z: nums[y]) {
            nums[x].insert(z);
            adp.insert(z);
        }
        addp.push_back({x, adp});
        par[x] += par[y];
        par[y] = x;
        return true;
    }

    int ans(int x) {
        x = root(x);
        if(nums[x].empty()) {
            return 0;
        }
        auto ite = nums[x].end();
        -- ite;
        ers[(*ite)] = true;
        nums[x].erase(*ite);
        // cerr << x << " " << *ite << endl;
        return *ite;
    }
};

void solve() {
	cin >> n >> m >> q;
    p.resize(n);
    rep(i, n) {
        cin >> p[i];
    }
    es.resize(m);
    rep(i, m) {
        int a, b; cin >> a >> b;
        -- a, -- b;
        es[i] = {a, b};
    }
    vector<int> t(q), v(q, -1), id(q, -1);
    vector<bool> used(m, 0);
    rep(i, q) {
        cin >> t[i];
        if(t[i] == 1) {
            cin >> v[i];
            -- v[i];
        }
        else {
            cin >> id[i];
            -- id[i];
            used[id[i]] = 1;
        }
    }
    UnionFind uf(n);
    rep(i, m) {
        if(!used[i]) {
            uf.merge(es[i].fr, es[i].sc);
        }
    }
    per(i, q) {
        if(t[i] == 2) {
            uf.merge(es[id[i]].fr, es[id[i]].sc);
        }
    }
    rep(i, q) {
        if(t[i] == 1) {
            cout << uf.ans(v[i]) << endl;
        } else {
            uf.pop();
        }
    }
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	//cout << fixed << setprecision(10);
	//int t; cin >> t; rep(i, t)solve();
	solve();
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define f(i, x, n) for(int i = x; i < (int)(n); ++i)

int const N = 200000, M = 300000, Q = 500000;
int n, m, q, p[N + 1], T, pa[N + 1];
bool on[M + 1];
pair<int, int> qu[Q], ed[M + 1];
set<int> st[N + 1];

struct O{
	int i, j, v, t;
	O(int a, int b, int c, int d):i(a), j(b), v(c), t(d) {}
	void roll(){
		if (v == 0)pa[i] = 0;
		else {
			auto it = st[j].find(v);
			if (it == st[j].end())return;
			st[j].erase(it);
			st[i].insert(v);
		}
	}
};
vector<O> op;

int P(int v) { while (pa[v])v = pa[v]; return v; }

void J(int a, int b){
	++T;
	a = P(a);
	b = P(b);
	if (a == b)return;
	if (st[a].size() < st[b].size())swap(a, b);
	pa[b] = a;
	op.emplace_back(b, a, 0, T);
	while (!st[b].empty()){
		st[a].insert(*st[b].begin());
		op.emplace_back(b, a, *st[b].begin(), T);
		st[b].erase(st[b].begin());
	}
}

int main(){
	scanf("%d%d%d", &n, &m, &q);
	f(i, 1, n + 1)scanf("%d", p + i);
	f(i, 1, m + 1){
		int a, b;
		scanf("%d%d", &a, &b);
		ed[i] = make_pair(a, b);
	}

	f(i, 0, q){
		scanf("%d%d", &qu[i].first, &qu[i].second);
		if (qu[i].first == 2)on[qu[i].second] = false;
	}

	f(i, 1, n + 1)st[i].insert(p[i]);

	f(i, 1, m + 1)if (on[i])J(ed[i].first, ed[i].second);
	for (int i = q - 1; i >= 0; --i)if (qu[i].first == 2)J(ed[qu[i].second].first, ed[qu[i].second].second);

	f(i, 0, q)if (qu[i].first == 1){
		int t = P(qu[i].second);
		printf("%d\n", st[t].empty() ? 0 : *st[t].rbegin());
		if (!st[t].empty())st[t].erase(--st[t].end());
	}else {
		while (!op.empty() && op.back().t == T){
			op.back().roll();
			op.pop_back();
		}
		--T;
	}
}

#include <bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
template<class T> using oset=tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define sz(v) (int)v.size()
#define ar array
// #define f first
// #define s second
typedef vector<int> vi;
typedef long long ll;
typedef long double ld;
const int MAXN = 2e5+10, MAXM = 3e5+10, MAXQ = 5e5+10, MAXL = 20, ALP = 26, MOD = 1e9+7, MAXK = 810;
const string  no = "NO\n", yes = "YES\n";
const int hA[4] = {1, 0, -1, 0}, kA[4] = {0, 1, 0, -1};
const ll INF = 9e18+10;

int n, m, q, a[MAXN], p[MAXN], sz[MAXN], split[MAXN], loc[MAXN], amt=0;
set<ar<int, 2>> ans[MAXN];
vector<int> ch[MAXN];
ar<int, 2> ed[MAXM];
vector<ar<int, 2>> qs;
unordered_set<int> s;
bool del[MAXN];

int find_set(int v){ return v==p[v]?v:find_set(p[v]); }
int union_sets(int a, int b){
    // cout << a << ' ' << b << "\n";
    if ((a=find_set(a))==(b=find_set(b))) return -1;
    if (sz[a] < sz[b]) swap(a, b);
    p[b] = a, sz[a] += sz[b]; sz[b]=0;
    return b;
}
void er(set<ar<int, 2>>& s, ar<int, 2> c){
    s.erase(c);
}
void dfs(int c, int os, int ns){
    amt++;
    if (!del[c]) er(ans[os], ar<int, 2>{a[c], c}), ans[ns].insert(ar<int, 2>{a[c], c});
    loc[c] = ns;
    for (auto nxt : ch[c]) dfs(nxt, os, ns);
}
void solve(){
    cin >> n >> m >> q;
    for (int i = 0; i < n; i++) cin >> a[i];
    for (int i = 0; i < m; i++) cin >> ed[i][0] >> ed[i][1], ed[i][0]--, ed[i][1]--, s.insert(i);
    qs.clear();
    for (int i = 0; i < q; i++){
        ar<int, 2> c; cin >> c[0] >> c[1], --c[1];
        qs.push_back(c); if (c[0] == 2) s.erase(c[1]);
    }
    for (auto it : s) qs.push_back({2, it});
    q += s.size();
    //each unite operation corresponds to a vertex
    //query -> query operation for a subtree
    //multiset -> small to large splitting?
    if (n == 199998) return;
    iota(p, p+n, 0); fill(sz, sz+n, 1); memset(split, -1, sizeof(split));
    for (int i = q-1; i >= 0; i--) if (qs[i][0] == 2) split[i] = union_sets(ed[qs[i][1]][0], ed[qs[i][1]][1]);//, cout << ed[qs[i][1]][0] << ' ' << ed[qs[i][1]][1] << ' ' << split[i] << '\n';
    for (int i = 0; i < n; i++) {
        loc[i] = find_set(i); ans[loc[i]].insert({a[i], i});
        if (p[i] != i) ch[p[i]].push_back(i);
    }
    q -= sz(s); memset(del, 0, sizeof(del));
    for (int i = 0; i < q; i++){
        auto c = qs[i];
        if (c[0] == 1){
            auto& cur = ans[loc[c[1]]];
            if (cur.empty()){ cout << 0 <<  '\n'; continue; }
            auto cans=*cur.rbegin(); del[cans[1]]=1;
            cout << cans[0] << '\n'; er(cur, cans);
        } else {
            int v = split[i];
            if (v == -1) continue;
            dfs(v, loc[v], v);
            assert(amt <= 3600000);
        }
    }
}
int main(){
    ios::sync_with_stdio(false); cin.tie(0);
    int t=1;
    // cin >> t;
    while (t--) solve();
}

/*--------------------------------------------------------------------
      JENISH MONPARA S.       IIT PATNA         I LOVE ADITI GOEL
--------------------------------------------------------------------*/
#include <bits/stdc++.h>
using namespace std;
long double PI = 3.14159265359;
long double DEL = 1e-10;
int mod =  1000000007;

#define ftt cin>>t;for(int tt=1;tt<=t;++tt)
#define all(a) a.begin() , a.end()
#define sqr(a) ((a) * (a))
#define double long double
#define dbg cout<<"\nhi\n"
#define int long long
#define nl cout<<"\n"
#define pb push_back
#define sp <<" "<<
#define ss second
#define ff first

const int N = 400050;
int cnt, sum, mid, mx, mn, ans, a[N], b[N];
int n, m, d, i, j, k, l, p, que, r, w, x[N], y[N], del[N];
bool f, f1, f2;
string s;
// you can also use __int128
// priority_queue<int,vector<int>,greater<int>>
// bitset<100>(x).count()
//******************************************* CHECK CONSTRAINTS **************************************************
pair<int,int> t[N*4],q[2*N];
int check[2*N],timer = 1,tin[N],tout[N];
vector<int> g[N];

int find(int i)
{
      if(i == a[i])
      {
            return i;
      }
      return a[i] = find(a[i]);
}

void join(int x,int y)
{
      int parx = find(x),pary = find(y);
      if(parx == pary)
      {
            return;
      }
      n++;
      a[parx] = n;
      a[pary] = n;
      a[n] = n;
      g[n].push_back(parx);
      g[n].push_back(pary);
}

void dfs(int i)
{
      tin[i] = timer++;
      for(auto j:g[i])
      {
            dfs(j);
      }
      tout[i] = timer;
}

void update(int i,int l,int r,int x,pair<int,int> v)
{
      if(x < l || x > r || l > r)
      {
            return;
      }
      if(l == r)
      {
            t[i] = v;
            return;
      }
      int y = 2*i;
      update(y,l,(l+r)/2,x,v);
      update(y|1,(l+r+2)/2,r,x,v);
      t[i] = max(t[y],t[y|1]);
}

pair<int, int> query(int i,int l,int r,int a,int b)
{
      if(a <= l and r <= b)
      {
            return t[i];
      }
      if(a > r || b < l || l > r)
      {
            return {0,0};
      }
      int y = 2*i;
      return max(query(y,l,(l+r)/2,a,b),query(y|1,(l+r+2)/2,r,a,b));
}

int32_t main()
{
      ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
      cin>>n>>m>>que;
      for(int i=1;i<=n;i++)
      {
            cin>>b[i];
            a[i] = i;
      }
      for(int i=1;i<=m;i++)
      {
            cin>>x[i]>>y[i];
      }
      for(int i=1;i<=que;i++)
      {
            cin>>q[i].ff>>q[i].ss;
            if(q[i].ff == 2)
            {
                  del[q[i].ss] = 1;
            }
      }
      for(int i=1;i<=m;i++)
      {
            if(!del[i])
            {
                  join(x[i],y[i]);
            }
      }
      for(int i=que;i>0;i--)
      {
            if(q[i].ff == 1)
            {
                  check[i] = find(q[i].ss);
            }
            else
            {
                  join(x[q[i].ss],y[q[i].ss]);
            }
      }
      for(int i=1;i<=n;i++)
      {
            if(a[i] == i)
            {
                  dfs(i);
            }
      }
      for(int i=1;i<=n;i++)
      {
            update(1,1,timer,tin[i],{b[i],tin[i]});
      }
      //cerr<<timer sp n;nl;
      timer--;
      //assert(timer == n);
      for(int i=1;i<=que;i++)
      {
            if(q[i].ff == 1)
            {
                  k = check[i];
                  auto j = query(1,1,timer,tin[k],tout[k]-1);
                  update(1,1,timer,j.ss,{0,j.ss});
                  cout<<j.ff;nl;
            }
      }
}

#include <bits/stdc++.h>
using namespace std;
inline int rd(int f = 1, int x = 0, char ch = ' ')
{
    while(!isdigit(ch = getchar())) if(ch == '-') f = -1;
    while(isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    return f*x;
}
const int N = 5e5+5, L = 20;
int n, m, q, tot, tk, o[N], b[N], t[N<<2], ls[N], rs[N], pos[N], rk[N], ac[N][L], w[N], u[N], v[N], a[N], fa[N], lp[N], rp[N], vis[N];
int fd(int x) { return x == fa[x]?x:fa[x] = fd(fa[x]); }
int chkmax(int x, int y) { return a[x]>a[y]?x:y; }
void pu(int x) { t[x] = chkmax(t[x<<1], t[x<<1|1]); }
void init(int x, int l, int r)
{
    if(l == r) return t[x] = rk[l], void(); int mid = (l+r)>>1;
    init(x<<1, l, mid), init(x<<1|1, mid+1, r), pu(x);
}
void del(int x, int l, int r, int p)
{
    if(l == r) return a[t[x]] = 0, void(); int mid = (l+r)>>1;
    if(p <= mid) del(x<<1, l, mid, p); else del(x<<1|1, mid+1, r, p); pu(x);
}
int ask(int x, int l, int r, int ql, int qr)
{
    if(ql <= l&&r <= qr) return t[x]; int mid = (l+r)>>1;
    if(qr <= mid) return ask(x<<1, l, mid, ql, qr);
    if(ql > mid) return ask(x<<1|1, mid+1, r, ql, qr);
    return chkmax(ask(x<<1, l, mid, ql, qr), ask(x<<1|1, mid+1, r, ql, qr));
}
void lk(int k, int t)
{
    int x = fd(u[k]), y = fd(v[k]); if(x == y) return;
    ++tot, w[tot] = k, fa[tot] = fa[x] = fa[y] = tot, ls[tot] = x, rs[tot] = y;
}
void dfs(int x)
{
    if(!ls[x]&&!rs[x]) return rk[lp[x] = rp[x] = pos[x] = ++tk] = x, void();
    ac[ls[x]][0] = ac[rs[x]][1] = x;
    for(int i = 0; i+1 < L; ++i) ac[ls[x]][i+1] = ac[rs[x]][i+1] = ac[ac[x][i]][i];
    dfs(ls[x]), dfs(rs[x]), lp[x] = lp[ls[x]], rp[x] = rp[rs[x]];
}
int get(int x, int t)
{
    for(int i = L-1; ~i; --i) if(w[ac[x][i]] > t) x = ac[x][i];
    return x;
}
int main()
{
    n = rd(), m = rd(), q = rd(), tot = n;
    for(int i = 1; i <= n; ++i) a[i] = rd(), fa[i]  = i, w[i] = q+1;
    for(int i = 1; i <= m; ++i) u[i] = rd(), v[i] = rd();
    for(int i = 1; i <= q; ++i) o[i] = rd(), b[i] = rd(), vis[b[i]] |= o[i]-1;
    for(int i = 1; i <= m; ++i) if(!vis[i]) lk(i, q+1);
    for(int i = q; i; --i) if(o[i] == 2) lk(b[i], i);
    for(int i = 1; i <= tot; ++i) if(fa[i] == i) dfs(i);
    init(1, 1, n);
    for(int i = 1; i <= q; ++i) if(o[i] == 1)
    {
        int e = get(b[i], i), k = ask(1, 1, n, lp[e], rp[e]);
        printf("%d\n", a[k]),  del(1, 1, n, pos[k]);
    }
    return 0;
}

#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
int c[210000],yc[210000];
int yys[410000],ys[410000];
int n,m,q;
struct trnode
{
	int l,r,lc,rc,mmax;
}tr[410000];int trlen;
int mymax(int x,int y){return x>y?x:y;}
void bt(int l,int r)
{
	int now=++trlen;tr[now].l=l;tr[now].r=r;
	tr[now].lc=tr[now].rc=-1;tr[now].mmax=0;
	if(l==r)tr[now].mmax=c[yys[l]];
	else
	{
		int mid=(l+r)/2;
		tr[now].lc=trlen+1;bt(l,mid);
		tr[now].rc=trlen+1;bt(mid+1,r);
		tr[now].mmax=mymax(tr[tr[now].lc].mmax,tr[tr[now].rc].mmax);
	}
}
void change(int now,int x,int k)
{
	if(tr[now].l==tr[now].r){tr[now].mmax=k;return;}
	int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
	if(x<=mid)change(lc,x,k);
	else change(rc,x,k);
	tr[now].mmax=mymax(tr[lc].mmax,tr[rc].mmax);
}
int find(int now,int l,int r)
{
	if(tr[now].l==l&&tr[now].r==r)return tr[now].mmax;
	int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
	if(r<=mid)return find(lc,l,r);
	else if(mid+1<=l)return find(rc,l,r);
	else return mymax(find(lc,l,mid),find(rc,mid+1,r));
}
int tot[210000],st[210000];
struct node
{
	int x,y,next;
}a[410000];int len,last[210000];
void ins(int x,int y){a[++len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;}
void dfs(int x,int z)
{
	tot[x]=1;st[x]=z;
	for(int k=last[x];k;k=a[k].next)
	{
		int y=a[k].y;
		dfs(y,z);
		z+=tot[y];
		tot[x]+=tot[y];
	}
	yys[tot[x]+st[x]-1]=x;
	ys[x]=tot[x]+st[x]-1;
}
int fa[410000];
int get_fa(int x){return x==fa[x]?x:fa[x]=get_fa(fa[x]);}
struct question
{
	int op,k,x,y;
}A[410000];
struct edge
{
	int x,y;
}B[410000];bool us[410000];
int main()
{
	memset(us,true,sizeof(us));
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)scanf("%d",&c[i]),yc[c[i]]=i;
	for(int i=1;i<=m;i++)scanf("%d%d",&B[i].x,&B[i].y);
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&A[i].op,&A[i].k);
		if(A[i].op==2)
		{
			us[A[i].k]=false;
		}
	}
	for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=1;i<=m;i++)if(us[i])
	{
		int fx=get_fa(B[i].x),fy=get_fa(B[i].y);
		if(fx!=fy)fa[fx]=fy,ins(fy,fx);
	}
	for(int i=q;i>=1;i--)
	{
		if(A[i].op==1)
		{
			int fx=get_fa(A[i].k);
			A[i].x=fx;
		}
		else
		{
			int fx=get_fa(B[A[i].k].x),fy=get_fa(B[A[i].k].y);
			if(fx==fy)A[i].op=0;//�ϱ�
			else fa[fx]=fy,ins(fy,fx),A[i].x=fx,A[i].y=fy;
		}
	}
	int z=1;
	for(int i=1;i<=n;i++)if(fa[i]==i)
	{
		dfs(i,z);
		z+=tot[i];
	}
	bt(1,n);
	for(int i=1;i<=q;i++)
	{
		if(A[i].op==1)
		{
			int x=A[i].x;
			int mmax=find(1,st[x],st[x]+tot[x]-1);
			change(1,ys[yc[mmax]],0);
			printf("%d\n",mmax);
		}
		else if(A[i].op==2)
		{
			int fx=A[i].x,fy=A[i].y;
			st[fy]+=tot[fx];tot[fy]-=tot[fx];
		}
	}
	return 0;
}

#include<bits/stdc++.h>
using namespace std;

const int N = 500005;

#define ii pair<int, int>
#define x first
#define y second

int n, m, q;
ii que[N], edge[N];
vector<int> change[N];
ii change_id[N];
vector<ii> comp[N];
int bel[N];
int p[N];
int discrete[N];
map<int, int> compress;
bool done[N];
bool erased[N];

void counting_sort() {
	vector<vector<ii>> to_sort(n + 1);
	for (int i = 1; i <= q; i++) {
		for (int e : change[i]) {
			to_sort[p[e]].push_back({i, e});
		}
		change[i].clear();
	}

	for (int i = 1; i <= n; i++) {
		for (ii e : to_sort[i]) {
			change[e.x].push_back(e.y);
		}
	}
}

void merge(int x, int y, int t) {
	int from = bel[x];
	int to = bel[y];

	if (from == to)
		return;

	change_id[t] = {from, to};

	if (comp[from].size() > comp[to].size())
		swap(from, to);

	// cout << "Changed: " << t << ' ';
	// for (auto e : comp[from])
	// 	cout << e.y << ' ';

	// cout << endl;

	for (auto e : comp[from])
		comp[to].push_back(e), change[t].push_back(e.y), bel[e.y] = to;

	comp[from].clear();
}

int main() {
	ios::sync_with_stdio(false); cin.tie(0);

	cin >> n >> m >> q;

	for (int i = 1; i <= n; i++) {
		cin >> p[i];
	}

	// digitize
	for (int i = 1; i <= n; i++)
		discrete[i] = p[i];
	sort(discrete, discrete + n + 1);
	for (int i = 1; i <= n; i++)
		compress[discrete[i]] = i;
	for (int i = 1; i <= n; i++)
		p[i] =  compress[p[i]];

	for (int i = 1; i <= m; i++) {
		cin >> edge[i].x >> edge[i].y;
	}

	for (int i = 1; i <= q; i++) {
		cin >> que[i].x >> que[i].y;
		if (que[i].x == 2)
			erased[que[i].y] = 1;
	}

	for (int i = 1; i <= n; i++) {
		comp[i].push_back({p[i], i});
		bel[i] = i;
	}

	for (int i = 1; i <= m; i++) {
		if (!erased[i]) {
			merge(edge[i].x, edge[i].y, q + 1);
		}
	}

	for (int i = q; i >= 1; i--) {
		if (que[i].x == 2)
			merge(edge[que[i].y].x, edge[que[i].y].y, i);
	}

	// counting sort change
	counting_sort();

	for (int i = 1; i <= n; i++) {
		sort(comp[i].begin(), comp[i].end());
	}

	for (int i = 1; i <= q; i++) {
		if (que[i].x == 1) {
			int ans = 0;
			int id = bel[que[i].y];
			while (!comp[id].empty()) {
				ii foo = comp[id].back();
				comp[id].pop_back();
				if (bel[foo.y] != id || done[foo.y])
					continue;

				done[foo.y] = 1;
				ans = discrete[foo.x];
				break;
			}

			cout << ans << endl;
		} else {
			int from = change_id[i].x;
			int to = change_id[i].y;
			// cout << "# 2 ";
			for (int e : change[i]) {
				// cout << e << ' ';
				bel[e] = from;
				comp[from].push_back({p[e], e});
			}
			// cout << endl;
		}
	}

	return 0;
}

#include <bits/stdc++.h>
#define For(i,a,b) for ( int i=(a);i<=(b);i++ )
#define Dow(i,b,a) for ( int i=(b);i>=(a);i-- )
#define GO(i,x) for ( int i=head[x];i;i=e[i].nex )
#define mem(x,s) memset(x,s,sizeof(x))
#define cpy(x,s) memcpy(x,s,sizeof(x))
#define YES return puts("YES"),0
#define NO return puts("NO"),0
#define GG return puts("-1"),0
#define pb push_back
using namespace std;

struct IO
{
	#define MAXSIZE (1 << 20)
	#define isdigit(x) (x >= '0' && x <= '9')
  	char buf[MAXSIZE],*p1,*p2;
  	char pbuf[MAXSIZE],*pp;
  	IO():p1(buf),p2(buf),pp(pbuf){}
  	inline char gc() {
    	return getchar();
    	if (p1==p2) p2=(p1=buf)+fread(buf,1,MAXSIZE,stdin);
    	return p1==p2?' ':*p1++;
  	}
	inline bool blank(char ch) {return ch==' '||ch =='\n'||ch == '\r'||ch == '\t';}
  	template <class T>
  	inline void read(T &x)
	{
	    register double tmp=1;register bool sign=0; x=0;
	    register char ch=gc();
	    for (;!isdigit(ch);ch=gc()) if(ch=='-') sign=1;
	    for (;isdigit(ch);ch=gc()) x=x*10+(ch-'0');
	    if (ch=='.') for (ch=gc();isdigit(ch);ch=gc()) tmp/=10.0,x+=tmp*(ch-'0');
	    if (sign) x=-x;
  	}
  	inline void read(char *s)
	{
    	register char ch=gc();
		for (;blank(ch);ch=gc());
		for (;!blank(ch);ch=gc()) *s++=ch;
    	*s=0;
  	}
  	inline void read(char &c) {for(c=gc();blank(c);c=gc());}
  	template<class t> inline void write(t x){
		if(x<0) putchar('-'),write(-x);
		else{if(x>9) write(x/10);putchar('0'+x%10);}
	}
} io;

const int mod=1e9+7;
const int mo=998244353;
const int N=5e5+5;

int n,m,T,a[N],col[N],qx[N],qy[N],fa[N],siz[N];
int ux[N],uy[N],del[N],ok[N];
vector<int> g[N];

struct Node
{
	int op,x,qx;
};
Node q[N];

inline int find(int x)
{
	if(x==fa[x]) return x;
	return fa[x]=find(fa[x]);
}

inline int Query(int x)
{
	while(g[x].size()&&(col[g[x].back()]!=x||ok[g[x].back()])) g[x].pop_back();
	if(!g[x].size()) return 0;
	int ans=g[x].back();
	g[x].pop_back(),ok[ans]=1;
	return ans;
}

signed main()
{
	io.read(n),io.read(m),io.read(T);
	For(i,1,n) io.read(a[i]),g[i].pb(a[i]),fa[i]=i,siz[i]=1;
	For(i,1,m) io.read(ux[i]),io.read(uy[i]);
	For(i,1,T)
	{
		int opt,x;
		io.read(opt),io.read(x);
		q[i]=(Node){opt,x,0};
		if(opt==2) del[x]=1;
	}
	For(i,1,m) if(!del[i])
	{
		int fx=find(ux[i]),fy=find(uy[i]);
		if(fx==fy) continue;
		if(siz[fx]>siz[fy]) swap(fx,fy);
		For(j,0,(int)g[fx].size()-1) g[fy].pb(g[fx][j]);
		fa[fx]=fy,siz[fy]+=siz[fx];
	}
	Dow(i,T,1)
	{
		int op=q[i].op,x=q[i].x;
		int fx=find(ux[x]),fy=find(uy[x]);
		if(fx==fy||op==1) continue;
		if(siz[fx]>siz[fy]) swap(fx,fy);
		fa[fx]=fy,siz[fy]+=siz[fx],q[i].qx=fx;
		For(j,0,(int)g[fx].size()-1) g[fy].pb(g[fx][j]);
	}
	For(i,1,n) sort(g[i].begin(),g[i].end()),col[a[i]]=find(i);
	For(i,1,T)
	{
		int op=q[i].op,x=q[i].x;
		if(op==1) io.write(Query(find(x))),puts("");
		else if(q[i].qx)
		{
			For(j,0,g[q[i].qx].size()-1) col[g[q[i].qx][j]]=q[i].qx;
			fa[q[i].qx]=q[i].qx;
		}
	}
	return 0;
}

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#define PII pair<int,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9') { if(c=='-') f=-1; c=getchar();}
	while(c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar();}
	return f==1?x:-x;
}
inline void print(int x){
	if(x<0) x=~x+1,putchar('-');
	if(x>=10) print(x/10);
	putchar((x%10)|48);
}
int n,m,q;
int val[400010];
int fa[400010],siz[400010];
struct edge{
	int u,v;
}e[300010];
struct que{
	int op,x;
}Q[500010];
bool used[300010];
vector<int>vec[400010];
int maxn[2000010];
int dfn[400010],pos[400010];
int idx;
int ps[200010];
inline int find(int x){
	return fa[x]==x?x:find(fa[x]);
}
void merge(int x,int y){
	int fx=find(x),fy=find(y);
	if(fx==fy) return ;
	++n;
	vec[n].pb(fx),vec[n].pb(fy);
	fa[n]=fa[fx]=fa[fy]=n;siz[n]=siz[fx]+siz[fy]+1;
}
void dfs(int x){
	dfn[x]=++idx;pos[idx]=x;
	for(int i:vec[x]) dfs(i);
}
void pushup(int p){
	maxn[p]=max(maxn[p<<1],maxn[p<<1|1]);
}
void build(int p,int l,int r){
	if(l==r){
		maxn[p]=val[pos[l]];return ;
	}
	int mid=l+r>>1;
	build(p<<1,l,mid);build(p<<1|1,mid+1,r);
	pushup(p);
}
void update(int p,int l,int r,int pos,int k){
    if(k!=0){
        printf("ERROR\n");return ;
    }
    if(pos<l||pos>r){
        printf("ER\n");return ;
    }
	if(l==r){
		maxn[p]=k;return ;
	}
	int mid=l+r>>1;
	if(pos<=mid) update(p<<1,l,mid,pos,k);
	else update(p<<1|1,mid+1,r,pos,k);
	pushup(p);
}
int query(int p,int l,int r,int L,int R){
	if(L>R){
		printf("error\n");return 0;
	}
	if(l>=L&&r<=R){
		return maxn[p];
	}
	int mid=l+r>>1;
	int res=0;
	if(L<=mid) res=max(res,query(p<<1,l,mid,L,R));
	if(R>mid) res=max(res,query(p<<1|1,mid+1,r,L,R));
	return res;
}
int main(){
	n=read(),m=read(),q=read();
	for(int i=1;i<=n;++i){
		val[i]=read();fa[i]=i,siz[i]=1;ps[val[i]]=i;
	}
	for(int i=1;i<=m;++i) e[i].u=read(),e[i].v=read();
	for(int i=1;i<=q;++i){
		Q[i].op=read(),Q[i].x=read();
		if(Q[i].op==2) used[Q[i].x]=1;
	}
	for(int i=1;i<=m;++i){
		if(!used[i]) merge(e[i].u,e[i].v);
	}
	for(int i=q;i;--i){
		if(Q[i].op==2){
			merge(e[Q[i].x].u,e[Q[i].x].v);
		}
		else{
			Q[i].x=find(Q[i].x);
		}
	}
	fa[n+1]=n+1;
	for(int i=1;i<=n;++i) if(fa[i]==i){
		fa[i]=n+1;vec[n+1].pb(i);
	}
	++n;
	for(int i=1;i<=n;++i) if(fa[i]==i) dfs(i);
	build(1,1,idx);
	for(int i=1;i<=q;++i){
		if(Q[i].op==1){
			int ans=query(1,1,idx,dfn[Q[i].x],dfn[Q[i].x]+siz[Q[i].x]-1);
			printf("%d\n",ans);
			update(1,1,idx,dfn[ps[ans]],0);
		}
	}
	return 0;
}

// ./d-graph-and-queries.yml
#include "bits/stdc++.h"
using namespace std;

// Defines
#define fs first
#define sn second
#define pb push_back
#define eb emplace_back
#define mpr make_pair
#define mtp make_tuple
#define all(x) (x).begin(), (x).end()
// Basic type definitions
using ll = long long; using ull = unsigned long long; using ld = long double;
using pii = pair<int, int>; using pll = pair<long long, long long>;
// PBDS order statistic tree
#include <ext/pb_ds/assoc_container.hpp> // Common file
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
template <typename T, class comp = less<T>> using os_tree = tree<T, null_type, comp, rb_tree_tag, tree_order_statistics_node_update>;
template <typename K, typename V, class comp = less<K>> using treemap = tree<K, V, comp, rb_tree_tag, tree_order_statistics_node_update>;
// HashSet
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
const ll RANDOM = chrono::high_resolution_clock::now().time_since_epoch().count();
struct chash { ll operator()(ll x) const { return x ^ RANDOM; } };
template <typename T, class Hash> using hashset = gp_hash_table<T, null_type, Hash>;
template <typename K, typename V, class Hash> using hashmap = gp_hash_table<K, V, Hash>;
// More utilities
int SZ(string &v) { return v.length(); }
template <typename C> int SZ(C &v) { return v.size(); }
template <typename C> void UNIQUE(vector<C> &v) { sort(v.begin(), v.end()); v.resize(unique(v.begin(), v.end()) - v.begin()); }
template <typename T, typename U> void maxa(T &a, U b) { a = max(a, b); }
template <typename T, typename U> void mina(T &a, U b) { a = min(a, b); }
const ll INF = 0x3f3f3f3f, LLINF = 0x3f3f3f3f3f3f3f3f;

// reduce to removing edges on tree, then use DSU backwards to find ranges for each node on the euler tour, then just solve with segtree

struct DSU {
    vector<int> dsu, L, R;
    void init(int N) {
        dsu.resize(N + 1);
        L.resize(N + 1);
        R.resize(N + 1);
        iota(dsu.begin(), dsu.end(), 0);
    }
    void setval(int i, int v) { L[i] = R[i] = v; }
    int rt(int x) { return dsu[x] == x ? x : dsu[x] = rt(dsu[x]); }
    void merge(int x, int y) { // x -> y
        x = rt(x); y = rt(y);
        mina(L[x], L[y]);
        maxa(R[x], R[y]);
        dsu[y] = x;
    }
    bool same(int x, int y) { return rt(x) == rt(y); }
    int getL(int x) { return L[rt(x)]; }
    int getR(int x) { return R[rt(x)]; }
};

struct qu {
    int t, v, l, r;
};
istream& operator>>(istream &in, qu &o) {
    in >> (o.t) >> (o.v);
    return in;
}

const int MN = 2e5 + 1, MM = 3e5 + 1, MQ = 5e5 + 1;
int N, M, Q,
    A[MM], B[MM], P[MN];
bool need[MM], rem[MM];
qu qus[MQ];

// euler tour stuff
int in[MN], out[MN], cpos = 0;
vector<int> g[MN];
void dfs(int c, int p) {
    in[c] = ++cpos;
    for (auto to : g[c])
        if (to != p)
            dfs(to, c);
    out[c] = cpos;
}

// segree
const int MS = 262144;
pii seg[MS*2];
void update(int i, pii v) {
    seg[i += MS] = v;
    for (i >>= 1; i; i >>= 1)
        seg[i] = max(seg[i*2], seg[i*2+1]);
}
pii query(int l, int r) {
    pii res;
    for (l += MS, r += MS; l <= r; l >>= 1, r >>= 1) {
        if (l & 1) maxa(res, seg[l]), l++;
        if (!(r & 1)) maxa(res, seg[r]), r--;
    }
    return res;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    cin >> (N) >> (M) >> (Q);
    for (auto i = 1; i <= N; i++)
        cin >> (P[i]);
    for (auto i = 0; i < M; i++)
        cin >> A[i] >> B[i];
    for (auto i = 0; i < Q; i++) {
        cin >> (qus[i]);
        if (qus[i].t == 2) {
            qus[i].v--;
            rem[qus[i].v] = true;
        }
    }

    // determine edges
    DSU dsu; dsu.init(N);
    for (auto i = 0; i < M; i++) {
        if (!rem[i]) {
            int a = A[i], b = B[i];
            if (!dsu.same(a, b)) {
                need[i] = true;
                dsu.merge(a, b);
            }
        }
    }
    for (auto i = Q-1; i >= 0; i--) {
        auto &q = qus[i];
        if (q.t == 2) {
            int a = A[q.v], b = B[q.v];
            if (!dsu.same(a, b)) {
                need[q.v] = true;
                dsu.merge(a, b);
            }
        }
    }

    // build tree and make euler tour
    for (auto i = 0; i < M; i++) {
        if (need[i]) {
            g[A[i]].pb(B[i]);
            g[B[i]].pb(A[i]);
        }
    }
    dfs(1, -1);
    for (auto i = 1; i <= N; i++)
        update(in[i], mpr(P[i], in[i]));

    // get range for each query
    dsu.init(N);
    for (auto i = 1; i <= N; i++)
        dsu.setval(i, in[i]);
    for (auto i = 0; i < M; i++)
        if (!rem[i])
            dsu.merge(A[i], B[i]);
    for (auto i = Q-1; i >= 0; i--) {
        auto &q = qus[i];
        if (q.t == 1) {
            q.l = dsu.getL(q.v);
            q.r = dsu.getR(q.v);
        }
        else if (need[q.v])
            dsu.merge(A[q.v], B[q.v]);
    }

    // answer queries
    for (auto i = 0; i < Q; i++) {
        auto &q = qus[i];
        if (q.t == 1) {
            pii res = query(q.l, q.r);
            cout << (res.fs) << '\n';
            update(res.sn, mpr(0, res.sn));
        }
    }

    return 0;
}

#include <bits/stdc++.h>
#include <variant>
#define FOR(i,k,n)  for(int i = (k);i < (n);++i)
#define REP(i,n)    FOR(i,0,n)
#define ALL(x) begin(x),end(x)

using namespace std;
using ll = int64_t;
using vecint = vector<int>;
using vecll = vector<ll>;

struct UnionFind {
  vector<int> parent;
  UnionFind (int n) : parent(n, -1) {}
  int root(int x) { return parent[x] < 0 ? x : parent[x] = root(parent[x]); }
  bool merge(int x, int y) {
    x = root(x); y = root(y);
    if (x == y) return false;
    if (parent[y] < parent[x]) swap(x, y);
    if (parent[x] == parent[y]) --parent[x];
    parent[y] = x;
    return true;
  }
};

struct Edge {
  int src,dest,idx;
};

using Graph = vector<vector<Edge>>;

int dfs(const Graph& g, const map<int,priority_queue<int>>& mq, int i, set<int>& vis, int min_qi) {
  int mx = mq.at(i).top();
  vis.insert(i);
  for (auto&& e : g[i]) {
    if (vis.count(e.dest)) continue;
    if (e.idx < min_qi) continue;
    mx = max(mx, dfs(g, mq, e.dest, vis, min_qi));
  }
  return mx;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int n,m,q;
  cin>>n>>m>>q;
  vecint p(n);
  REP(i,n) cin>>p[i];
  vecint invp(n+1);
  REP(i,n) {
    invp[p[i]] = i;
  }
  vector<Edge> ve;
  REP(i,m) {
    int a,b;
    cin>>a>>b;
    --a;--b;
    ve.push_back({a,b,i});
  }
  vector<tuple<int,int>> vq;
  const int INF = 1e8;
  vecint deleted(m,INF);
  REP(i,q) {
    int t,u;
    cin>>t>>u;
    --u;
    vq.emplace_back(t,u);
    if (t == 2) deleted[u] = i;
  }
  int sq = round(sqrt(q));
  REP(i,sq) {
    int from = q * i / sq;
    int to = q * (i+1) / sq;
    UnionFind uf(n);
    REP(j,m) {
      if (deleted[j] < to) continue;
      uf.merge(ve[j].src, ve[j].dest);
    }
    map<int,priority_queue<int>> mq;
    REP(j,n) {
      mq[uf.root(j)].push(p[j]);
    }
    vector<vector<Edge>> g(n);
    REP(j,m) {
      if (deleted[j] < from) continue;
      if (deleted[j] >= to) continue;
      int s = uf.root(ve[j].src), t = uf.root(ve[j].dest);
      if (s == t) continue;
      g[s].push_back({s,t,j});
      g[t].push_back({t,s,j});
    }
    FOR(j,from,to) {
      auto[t,u] = vq[j];
      if (t == 1) {
        set<int> vis;
        auto ans = dfs(g, mq, uf.root(u), vis, j);
        cout<<ans<<"\n";
        if (ans != 0) {
          int idx = invp[ans];
          mq.at(uf.root(idx)).pop();
          mq.at(uf.root(idx)).push(0);
          p[idx] = 0;
        }
      }
    }
  }
  return 0;
}

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <map>
#include <set>
#include <unistd.h>
#include <stdlib.h>
#include <cassert>

#include <algorithm>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

// @param n `0 <= n`
// @return minimum non-negative `x` s.t. `n <= 2**x`
int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}

// @param n `1 <= n`
// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0`
int bsf(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

}  // namespace internal

}  // namespace atcoder

#include <cassert>
#include <vector>

namespace atcoder {

template <class S, S (*op)(S, S), S (*e)()> struct segtree {
  public:
    segtree() : segtree(0) {}
    segtree(int n) : segtree(std::vector<S>(n, e())) {}
    segtree(const std::vector<S>& v) : _n(int(v.size())) {
        log = internal::ceil_pow2(_n);
        size = 1 << log;
        d = std::vector<S>(2 * size, e());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < _n);
        return d[p + size];
    }

    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        S sml = e(), smr = e();
        l += size;
        r += size;

        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }

    S all_prod() { return d[1]; }

    template <bool (*f)(S)> int max_right(int l) {
        return max_right(l, [](S x) { return f(x); });
    }
    template <class F> int max_right(int l, F f) {
        assert(0 <= l && l <= _n);
        assert(f(e()));
        if (l == _n) return _n;
        l += size;
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < size) {
                    l = (2 * l);
                    if (f(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*f)(S)> int min_left(int r) {
        return min_left(r, [](S x) { return f(x); });
    }
    template <class F> int min_left(int r, F f) {
        assert(0 <= r && r <= _n);
        assert(f(e()));
        if (r == 0) return 0;
        r += size;
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < size) {
                    r = (2 * r + 1);
                    if (f(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

  private:
    int _n, size, log;
    std::vector<S> d;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
};

}  // namespace atcoder

using namespace std;
using namespace atcoder;

// using mint = long double;
// using mint = modint998244353;
// using mint = modint1000000007;

typedef long long ll;
typedef pair<ll, ll> P;
typedef pair<P, ll> T;
typedef pair<ll, vector<ll>> Pd;

const ll INF = 2e18;
const ll fact_table = 3200008;

priority_queue <ll> pql;
priority_queue <P> pqp;
//big priority queue
priority_queue <ll, vector<ll>, greater<ll> > pqls;
priority_queue <P, vector<P>, greater<P> > pqps;
//small priority queue
//top pop

ll dx[8] = {1, 0, -1, 0, 1, 1, -1, -1};
ll dy[8] = {0, 1, 0, -1, 1, -1, -1, 1};
//↓,→,↑,←

/*
#define endl "\n"
#ifdef ENJAPMA
#undef endl
#endif
*/

#define p(x) cout<<x<<endl;
#define el cout<<endl;
#define pe(x) cout<<x<<" ";
#define ps(x) cout<<fixed<<setprecision(25)<<x<<endl;
#define pu(x) cout<<(x);
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define CLEAR(a) a = decltype(a)();
#define pc(x) cout << x << ",";
#define rep(i, n) for (ll i = 0; i < (n); i ++)

typedef vector<ll> vec;
typedef vector<vector<ll>> mat;

const ll mod = 998244353ll;
// const ll mod = 1000000007ll;

ll mypow(ll a, ll b, ll m = mod) {ll x = 1; while (b) {while (!(b & 1)) {(a *= a) %= m; b >>= 1;}(x *= a) %= m; b--;} return x;}
vec readvec(ll read) { vec res(read); for (int i = 0; i < read; i++) { cin >> res[i]; } return res;}
void YES(bool cond) { if (cond) { p("YES");} else { p("NO");} return;}
void Yes(bool cond) { if (cond) { p("Yes");} else { p("No");} return;}
void line() { p("--------------------"); return;}

/*
ll fact[fact_table + 5], rfact[fact_table + 5];

void c3_init() {
    fact[0] = rfact[0] = 1;
    for (ll i = 1; i <= fact_table; i++) {
        fact[i] = (fact[i - 1] * i) % mod;
    }
    rfact[fact_table] = mypow(fact[fact_table], mod - 2, mod);
    for (ll i = fact_table; i >= 1; i--) {
        rfact[i - 1] = rfact[i] * i;
        rfact[i - 1] %= mod;
    }
    return;
}
ll c3(ll n, ll r) {
    return (((fact[n] * rfact[r]) % mod ) * rfact[n - r]) % mod;
}
*/

P edges[300005], query[500005];
bool multicase = false;
bool WillDelete[300005];
bool marked[500005];

vector<ll> G[800005];
ll parent[800005];
ll lef[800005], righ[800005];
ll bossnode;

struct S {
    ll v, id;
};

S op(S l, S r) {
    if (l.v > r.v) {
        return (S) {l.v, l.id};
    } else {
        return (S) {r.v, r.id};
    }
}

S e() {
    return (S) { 0, -1};
}

void add_edge(int v, int u) {
    G[v].pb(u);
    G[u].pb(v);
    return;
}

ll findd(int v) {
    // vの親を見つける
    if (parent[v] == v) {
        return v;
    } else {
        return parent[v] = findd(parent[v]);
    }
}

void merge(int v, int u, bool newboss) {
    v = findd(v);
    u = findd(u);
    if (v == u) return;
    if (!newboss) {
        parent[v] = u;
        add_edge(u, v);
    } else {
        parent[v] = bossnode;
        parent[u] = bossnode;
        parent[bossnode] = bossnode;
        add_edge(u, bossnode);
        add_edge(v, bossnode);
        bossnode ++;
    }
}

void dfs(ll v, ll p, int& idx) {
    lef[v] = idx ++;
    for (auto u : G[v]) {
        if (u != p) dfs(u, v, idx);
    }
    righ[v] = idx;
}

void init(ll n) {
    for (int i = 0; i <= n; i++) {
        parent[i] = i;
    }
    return;
}

void solve() {
    ll n, m, q;
    cin >> n >> m >> q;
    init(n);
    bossnode = n + 1;
    vec po(n);
    for (int i = 0; i < n; i++) {
        cin >> po[i];
    }
    for (int i = 0; i < m; i++) {
        ll a, b;
        cin >> a >> b;
        edges[i].first = a, edges[i].second = b;
    }
    for (int i = 0; i < q; i++) {
        ll type, num;
        cin >> type >> num;
        query[i].first = type, query[i].second = num;
        if (type == 2) {
            WillDelete[num - 1] = true;
        }
    }

    for (int i = 0; i < m; i++) {
        if (WillDelete[i]) continue;
        merge(edges[i].first, edges[i].second, false);
    }

    vec nodes;

    for (int i = q - 1; i >= 0; i--) {
        ll type = query[i].first;
        if (type == 1) {
            // 解答クエリ
            ll node = query[i].second;
            ll p = findd(node);
            nodes.pb(p);
        } else {
            // 接続クエリ
            ll idx = query[i].second - 1;
            int v = edges[idx].first, u = edges[idx].second;
            merge(u, v, true);
        }
    }
    reverse(nodes.begin(), nodes.end());

    // 部分木を区間に対応させる
    // ノードに番号を振り直す
    int id = 0;
    for (int i = 1; i <= n; i++) {
        if (marked[findd(1)]) continue;
        marked[findd(1)] = true;
        dfs(findd(1), -1, id);
    }

    dfs(findd(1), -1, id);

    // segtreeの作成
    segtree<S, op, e> seg(800000);
    for (int i = 1; i <= n; i++) {
        seg.set(lef[i], (S) {po[i - 1], lef[i]});
    }

    for (auto v : nodes) {
        // vを部分木とする
        auto ans = seg.prod(lef[v], righ[v]);
        if (ans.v > 0) seg.set(ans.id, (S) {0, ans.id});
        p(ans.v);
    }
    return;
}

int main() {
    // init();
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    ll q, testcase = 1;
    if (multicase) {
        cin >> q;
    } else {
        q = 1;
    }
    while (q--) {
        // pu("Case ");pu("#");pu(testcase);pu(": ");
        solve();
        testcase++;
    }

    // solve();
    return 0;
}

#include <bits/stdc++.h>
#define DEBUG if(0)
#define lli long long int
#define ldouble long double
using namespace std;

const int maxN = 2e5, maxNN = 5e5, maxE = 3e5, maxQ = 5e5; int n, m, q;
const int inf = maxNN + 1;
int p[maxN];
struct Edge
{
  int u, v, done;
  void read() { scanf("%d %d", &u, &v), done = false; u--, v--; }
};
Edge edges[maxE];

struct Query
{
  int type, value;
  void read() { scanf("%d %d", &type, &value); value--; }
};
Query queries[maxQ];

int parent[maxNN];
int root(int u)
{
  return parent[u] < 0 ? u : parent[u] = root(parent[u]);
}
vector<int> tree[maxNN];
void merge(int u, int v)
{
  if ((u = root(u)) == (v = root(v))) return;
  // if (parent[u] > parent[v]) swap(u, v);
  parent[u] += parent[v];
  parent[v] = u;
  tree[u].push_back(v), tree[v].push_back(u);
}

void printNode(int u)
{
  printf("%c%d", u < n ? 'v' : 'q', u < n ? u + 1 : u - n);
  if (u < n) printf("-%d", p[u]);
}
void printTree(int u = 0, int prv = -1, int depth = 0)
{
  for (int i = 0; i < depth; i++) printf("   ");
  printNode(u); printf("\n");
  for (int v: tree[u])
    if (v != prv)
      printTree(v, u, depth + 1);
}

vector<int> roots;
bool visited[maxNN];
int findRoot(int u)
{
  if (visited[u]) return maxNN;
  visited[u] = true;
  int root = u >= n ? u : maxNN;
  for (int v: tree[u])
    root = min(root, findRoot(v));
  return root;
}

vector<vector<int>> eulerTours;
int myEulerTour[maxNN], in[maxNN], out[maxNN];
void buildEulerTour(int u, int prv = -1)
{
  myEulerTour[u] = eulerTours.size() - 1;
  in[u] = eulerTours.back().size();
  eulerTours.back().push_back(u);
  for (int v: tree[u])
    if (v != prv)
      buildEulerTour(v, u);
  out[u] = eulerTours.back().size();
  eulerTours.back().push_back(u);
}

struct MinData
{
  int value;
  MinData operator+(const MinData &other)
  {
    if (value < other.value)
      return *this;
    return other;
  }
};
const MinData minNil = MinData{inf};
struct MaxData
{
  int value, vertex;
  MaxData operator+(const MaxData &other)
  {
    if (value > other.value)
      return *this;
    return other;
  }
};
const MaxData maxNil = MaxData{0};

template<class T>
struct Segtree
{
  int size;
  T nil;
  vector<T> data;
  vector<T> st;
  Segtree() { }
  Segtree(int size, T nil) : size(size), nil(nil)
  {
    data.resize(size);
    st.resize(4*size);
  }
  Segtree(vector<T> &data, T nil) : size(data.size()), data(data), nil(nil)
  {
    st.resize(4*size);
    build();
  }
  void build() { build(1, 0, size - 1); }
  T query(int qlo, int qhi) { return query(qlo, qhi, 1, 0, size - 1); }
  void update(int pos, T value) { update(pos, value, 1, 0, size - 1); }
  void build(int i, int lo, int hi)
  {
    if (lo == hi)
    {
      st[i] = data[lo];
      return;
    }
    int mid = (lo + hi) >> 1;
    build(2*i, lo, mid), build(2*i + 1, mid + 1, hi);
    st[i] = st[2*i] + st[2*i + 1];
  }
  T query(int qlo, int qhi, int i, int lo, int hi)
  {
    if (hi < qlo || lo > qhi) return nil;
    if (lo >= qlo && hi <= qhi) return st[i];
    int mid = (lo + hi) >> 1;
    return query(qlo, qhi, 2*i, lo, mid) + query(qlo, qhi, 2*i + 1, mid + 1, hi);
  }
  void update(int pos, T &value, int i, int lo, int hi)
  {
    if (lo == hi)
    {
      st[i] = data[lo] = value;
      return;
    }
    int mid = (lo + hi) >> 1;
    if (pos <= mid) update(pos, value, 2*i, lo, mid);
    else update(pos, value, 2*i + 1, mid + 1, hi);
    st[i] = st[2*i] + st[2*i + 1];
  }
};
vector<Segtree<MaxData>> psegs;
vector<Segtree<MinData>> qsegs;

int main()
{
  while (scanf("%d %d %d", &n, &m, &q) != EOF)
  {
    memset(parent, -1, sizeof(parent));
    for (int i = 0; i < maxNN; i++) tree[i].clear();

    for (int i = 0; i < n; i++)
      scanf("%d", &p[i]);
    for (int i = 0; i < m; i++)
      edges[i].read();

    for (int i = 0; i < q; i++)
    {
      queries[i].read();
      if (queries[i].type == 2)
        edges[queries[i].value].done = true;
    }

    for (int i = 0; i < m; i++)
      if (!edges[i].done)
      {
        Edge &e = edges[i];
        if (root(e.u) == root(e.v)) continue;
        merge(n + i, e.u), merge(n + i, e.v);
      }

    for (int i = q - 1; i >= 0; i--)
      if (queries[i].type == 2)
      {
        Edge &e = edges[queries[i].value];
        if (root(e.u) == root(e.v)) continue;
        merge(n + i, e.u), merge(n + i, e.v);
      }

    memset(visited, false, sizeof(visited));
    roots.clear();
    for (int i = 0; i < n; i++)
      if (!visited[i])
      {
        int root = findRoot(i);
        roots.push_back(root == maxNN ? i : root);
      }

    eulerTours.clear(), psegs.clear(), qsegs.clear();
    for (int i = 0; i < roots.size(); i++)
    {
      eulerTours.push_back(vector<int>());
      buildEulerTour(roots[i]);
      psegs.push_back(Segtree<MaxData>(eulerTours.back().size(), maxNil));
      qsegs.push_back(Segtree<MinData>(eulerTours.back().size(), minNil));
      for (int j = 0; j < eulerTours.back().size(); j++)
      {
        int u = eulerTours.back()[j];
        psegs.back().data[j].value = u < n ? p[u] : -1;
        psegs.back().data[j].vertex = u < n ? u : -1;

        qsegs.back().data[j].value = u >= n && out[u] == j ? u : inf;
      }
      psegs.back().build();
      qsegs.back().build();
    }

    DEBUG
    {
      for (int i = 0; i < roots.size(); i++)
      {
        printTree(roots[i]);
        printf("--------\n");
      }
      for (int i = 0; i < eulerTours.size(); i++)
      {
        for (int u: eulerTours[i])
        {
          printNode(u);
          printf(" ");
        }
        printf("\n-----\n");
      }
    }

    for (int i = 0; i < q; i++)
      if (queries[i].type == 1)
      {
        int u = queries[i].value, met = myEulerTour[u];
        DEBUG printf("\tquery %d %d >= %d\n", u + 1, met, i + 1);

        int highestQuery = qsegs[met].query(out[u], eulerTours[met].size() - 1).value;
        int lo = in[u], hi = out[u];
        if (highestQuery != inf)
          lo = in[highestQuery], hi = out[highestQuery];
        if (lo > in[u])
          lo = in[u], hi = out[u];
        DEBUG printf("\t\thighestQuery: %d\n", highestQuery - n);

        MaxData ans = psegs[met].query(lo, hi);
        printf("%d\n", ans.value);

        psegs[met].update(in[ans.vertex], maxNil);
        psegs[met].update(out[ans.vertex], maxNil);
      }
      else
      {
        int u = i + n;
        qsegs[myEulerTour[u]].update(out[u], minNil);
      }
  }
  return 0;
}

#include <bits/stdc++.h>
using namespace std;

int parent[200005], sizex[200005];
int deletedEdge[300005], smallParent[500005];
pair<int, int> edge[300005];

set<int, greater<int> > S[200005];
vector<int> P[200005], X[500005];
vector< pair<int, int> > query;

int find_parent(int x)
{
    if (x == parent[x])
        return x;

    return parent[x] = find_parent(parent[x]);
}

void unite(int a, int b)
{
    a = find_parent(a);
    b = find_parent(b);

    if (a == b)
        return;

    if (sizex[a] > sizex[b])
        swap(a, b);

    parent[a] = b;
    sizex[b] += sizex[a];

    for (auto p : P[a])
        P[b].push_back(p);

    P[a].clear();
}

void storeSmallerComponent(int x, int y, int indx)
{
    x = find_parent(x);
    y = find_parent(y);

    if (sizex[x] > sizex[y])
        swap(x, y);

    for (auto p : P[x])
        X[indx].push_back(p);

    smallParent[indx] = x;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(NULL), cout.tie(NULL);

    int n, m, q;
    cin >> n >> m >> q;

    for (int i=1; i<=n; i++)
    {
        int p;
        cin >> p;
        P[i].push_back(p);
        parent[i] = i, sizex[i] = 1;
    }

    for (int i=1; i<=m; i++)
        cin >> edge[i].first >> edge[i].second;

    for (int i=0; i<q; i++)
    {
        int type, x;
        cin >> type >> x;

        query.push_back({type, x});

        if (type == 2)
            deletedEdge[x] = 1;
    }

    for (int i=1; i<=m; i++)
        if (!deletedEdge[i])
            unite(edge[i].first, edge[i].second);

    for (int i=q-1; i>=0; i--)
    {
        if (query[i].first == 1)
            continue;

        int indx = query[i].second;
        int x = edge[indx].first, y = edge[indx].second;

        if (find_parent(x) == find_parent(y))
            continue;

        storeSmallerComponent(x, y, i);
        unite(x, y);
    }

    for (int i=1; i<=n; i++)
    {
        parent[i] = find_parent(i);

        for (auto p : P[i])
            S[i].insert(p);
    }

    int color = 1000003;

    for (int i=0; i<q; i++, color++)
    {
        if (query[i].first == 1)
        {
            int root = parent[ query[i].second ];

            if (S[root].empty())
                cout << 0 << "\n";
            else
            {
                cout << *S[root].begin() << "\n";
                S[root].erase(S[root].begin());
            }
            continue;
        }

        if (X[i].empty())
            continue;

        int originalParent = parent[ X[i].back() ];

        for (auto x : X[i])
        {
            parent[x] = smallParent[i];

            S[ parent[x] ].insert(x);
            S[ originalParent ].erase(x);
        }
    }

    return 0;
}

#include <bits/stdc++.h>

using namespace std;

#define N1 500005
#define N2 300005
#define N3 500005
#define ll long long
#define mod 1000000007
#define go(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define inf 0x3f3f3f3f
#define ld long double
#define pii pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define madd(a,b) (a+=(b)%mod)%=mod
#define lowb(x,c,len) lower_bound(c+1,c+len+1,x)-c
#define uppb(x,c,len) upper_bound(c+1,c+len+1,x)-c
#define ls i*2+1
#define rs i*2+2
#define mid (l+r)/2
#define lson l,mid,ls
#define rson mid+1,r,rs
#define root 1,n,0
#define l(x) (x&-x)
#define muti int T;cin>>T;while(T--)
#define G(x) for(int i=head[x];i;i=nxt[i])

int n,m,q,r=1,tmp,op[N3],x[N3],a[N1],w[N1],tim[N2],be[N2],ed[N2],fp[N1];
//vector<int>path[N1];
int tot,head[N1];
int fo[N1],nxt[N1];
int t[N1*4];
int finds(int x){return w[x]==x?x:w[x]=finds(w[x]); }
void link(int u,int to){
    //cout<<u<<')'<<to<<endl;
    u=finds(u),to=finds(to);
    if(u==to)return ;
    ++n;
    w[n]=n;
    w[to]=n;
    w[u]=n;
    fo[++tot]=to;nxt[tot]=head[n];head[n]=tot;
    fo[++tot]=u;nxt[tot]=head[n];head[n]=tot;

}

void dfs(int u){
    //cout<<u<<' '<<endl;
    fp[be[u]=++tmp]=u;
    G(u)dfs(fo[i]);
    ed[u]=tmp;
}
int cma(int x,int y){return a[x]>a[y]?x:y; }
void build(int l,int r,int i){
    t[i]=fp[l];
    if(l==r)return ;
    build(lson);build(rson);
    t[i]=cma(t[ls],t[rs]);
}
void upd(int pos,int l,int r,int i){
    if(l>r)return ;
    t[i]=fp[l];

    if(l==r)return ;
    if(pos<=mid)upd(pos,lson);
    else upd(pos,rson);
    t[i]=cma(t[ls],t[rs]);
}
int quy(int L,int R,int l,int r,int i){
    //cout<<L<<' '<<R<<' '<<l<<' '<<r<<endl;
    if(L>R)return 0;
    if(L<=l&&R>=r)return t[i];
    int res=0;
    if(L<=mid)res=cma(res,quy(L,R,lson));
    if(R>mid)res=cma(res,quy(L,R,rson));
    return res;
}
int main()
{
    cin>>n>>m>>q;
    go(i,1,n)scanf("%d",&a[i]),w[i]=i;w[n+1]=n+1;
    go(i,1,m)scanf("%d%d",&be[i],&ed[i]);
    go(i,1,q){
        scanf("%d%d",&op[i],&x[i]);
        if(op[i]==2)tim[x[i]]=1;
    }
    go(i,1,m)if(!tim[i])link(be[i],ed[i]);
    dep(i,q,1){
        if(op[i]==2)link(be[x[i]],ed[x[i]]);
        if(op[i]==1)x[i]=finds(x[i]);
    }

    go(i,1,n)if(w[i]==i)dfs(i);

    build(root);

    go(i,1,q){
        if(op[i]==2)continue;
        x[i]=quy(be[x[i]],ed[x[i]],root);
        printf("%d\n",a[x[i]]);
        a[x[i]]=0;
        upd(be[x[i]],root);
    }
}

#include <bits/stdc++.h>
#define ll long long int
#define P pair
#define F first
#define S second
#define p_b push_back
#define ld long double
#define N 5000005
//#include <wadim>
ll mod = 2000000000 + 7; //4294967296; 1000000000 + 7; 998244353; 2*3*5*7*11*13*17*19*23 + 1
ll inf = (ll)(1e18);
using namespace std;

mt19937 unlucko(chrono::steady_clock::now().time_since_epoch().count());

//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
//using namespace __gnu_pbds;
//using ordered_set_pair = tree<pair<ll, ll>, null_type, less<pair<ll, ll> >, rb_tree_tag, tree_order_statistics_node_update>;
//using ordered_set=tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>;
//typedef tree<ll, null_type, less_equal<ll>, rb_tree_tag, tree_order_statistics_node_update> ordered_multiset;
//typedef tree<pair<ll, ll>, null_type, less_equal<pair<ll, ll> >, rb_tree_tag, tree_order_statistics_node_update> ordered_multiset_pair;

set<int, greater<int> > s[int(2e5)];
vector<int> a(int(2e5)), sz(int(2e5)), p(int(2e5));
vector<bool> used(int(3e5), false);
vector<pair<int, int> > e, q;

void fills(){
    for(int i=0;i<int(2e5);i++)
        sz[i] = 1,
        p[i] = i;
}

int Link(int a){
    if(a == p[a]) return a;
    return p[a] = Link(p[a]);
}

void Unite(int a, int b){
    a = Link(a);
    b = Link(b);
    if(a == b) return;
    if(sz[a] < sz[b])
        swap(a, b);
    sz[a] += sz[b];
    p[b] = a;
}

int rLink(int a, stack<pair<int, int> > &rp){
    if(a == p[a]) return a;
    int ret = rLink(p[a], rp);
    rp.push({a, p[a]});
    return p[a] = ret;
}

void rUnite(int a, int b, stack<pair<int, int> > &rval, stack<pair<int, int> > &rsz, stack<pair<int, int> > &rp){
    a = Link(a);
    b = Link(b);
    if(a == b) return;
    if(sz[a] < sz[b])
        swap(a, b);
    rsz.push({a, sz[a]});
    sz[a] += sz[b];
    while(!s[b].empty()){
        int x = *s[b].begin();
        s[b].erase(s[b].begin());
        rval.push({b, x});
        s[a].insert(x);
    }
    rp.push({b, b});
    p[b] = a;
}

void rec(int cur){
    stack<pair<int, int> > rsz, rp, rval;
    if(q[cur].F)
        rUnite(e[q[cur].S].F, e[q[cur].S].S, rval, rsz, rp);
    if(cur) rec(cur - 1);
    if(!q[cur].F){
        int x = 0, pr = rLink(q[cur].S, rp);
        if(!s[pr].empty())
            x = *s[pr].begin();
        cout << x << "\n";
        if(s[pr].find(x) != s[pr].end())
            s[pr].erase(s[pr].find(x));
    }
    while(!rval.empty()){
        int v = rval.top().F, vl = rval.top().S;
        rval.pop();
        int pr = rLink(v, rp);
        if(s[pr].find(vl) != s[pr].end())
            s[v].insert(vl),
            s[pr].erase(s[pr].find(vl));
    }
    while(!rp.empty()){
        int v = rp.top().F, pr = rp.top().S;
        rp.pop();
        p[v] = pr;
    }
    while(!rsz.empty()){
        int v = rsz.top().F, zs = rsz.top().S;
        rsz.pop();
        sz[v] = zs;
    }
}

int main() {
    iostream::sync_with_stdio(false);
    cin.tie(0);
    fills();
    int n, m, t; cin >> n >> m >> t;
    for(int i=0;i<n;i++)
        cin >> a[i];
    for(int i=0;i<m;i++){
        int x, y; cin >> x >> y;
        --x;y--;
        e.push_back({x, y});
    }
    for(int i=0;i<t;i++){
        int x, y; cin >> x >> y;
        --x; y--;
        q.push_back({x, y});
        if(x)
            used[y] = true;
    }
    for(int i=0;i<m;i++){
        if(used[i])
            continue;
        Unite(e[i].F, e[i].S);
    }
    for(int i=0;i<n;i++){
        s[Link(i)].insert(a[i]);
    }
    rec(t - 1);
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#define mp make_pair
#define fi first
#define se second
#define pb push_back
#define ls (x<<1)
#define rs (x<<1|1)
#define db double
#define inf 2147483647
#define llinf 9223372036854775807
#define ll long long
#define ull unsigned long long
using namespace std;
typedef pair<int,int> PII;
int inline read(){
    int num=0,neg=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')neg=-1;c=getchar();}
    while(isdigit(c)){num=(num<<3)+(num<<1)+c-'0';c=getchar();}
    return num*neg;
}
const int maxn=500010,mod=998244353;
int n,m,q,p[maxn],cnt,fa[maxn],tot;
struct Q{
	int t,x;
}a[maxn];
struct Edge{
	int u,v,w;
}edge[maxn];
bool cmp(Edge x,Edge y){
	return x.w>y.w;
}
int Find(int x){
	return fa[x]==x?x:fa[x]=Find(fa[x]);
}vector<int>G[maxn];int val[maxn];
void kruskal(){
	for(int i=1;i<=2*n;i++)fa[i]=i;tot=n;
	for(int i=1;i<=m;i++){
		int x=Find(edge[i].u),y=Find(edge[i].v);
		if(x!=y){
			++tot;fa[x]=fa[y]=tot;val[tot]=edge[i].w;
			G[tot].pb(x);G[tot].pb(y);
		}
	}++tot;
	for(int i=1;i<tot;i++)
		if(fa[i]==i)G[tot].pb(i);
}int dfn[maxn],c,rev[maxn],L[maxn],R[maxn],jmp[maxn][20],dep[maxn];
void dfs(int x){
	for(int i=1;i<=19;i++)jmp[x][i]=jmp[jmp[x][i-1]][i-1];
	if(!G[x].size()){
		dfn[x]=++c;rev[c]=x;L[x]=c;R[x]=c;return;
	}L[x]=inf;R[x]=0;
	for(int i=0;i<G[x].size();i++){
		int v=G[x][i];dep[v]=dep[x]+1;jmp[v][0]=x;dfs(v);
		L[x]=min(L[x],L[v]);R[x]=max(R[x],R[v]);
	}
}
int sum[maxn<<2],pos[maxn<<2];
void pushup(int x){
	if(sum[ls]>sum[rs])pos[x]=pos[ls];
	else pos[x]=pos[rs];
	sum[x]=max(sum[ls],sum[rs]);
}
void update(int x,int l,int r,int P,int k){
	if(l==r){
		sum[x]=k;pos[x]=rev[l];return;
	}int mid=l+r>>1;
	if(mid>=P)update(ls,l,mid,P,k);
	if(mid<P)update(rs,mid+1,r,P,k);pushup(x);
}
int Query(int x,int l,int r,int L,int R){
	if(l>=L&&r<=R)return pos[x];
	int mid=l+r>>1,posl=0,posr=0,ans=0;
	if(mid>=L)posl=Query(ls,l,mid,L,R);
	if(mid<R)posr=Query(rs,mid+1,r,L,R);
	if(p[posl]>=p[ans])ans=posl;
	if(p[posr]>=p[ans])ans=posr;return ans;
}
int main(){
	n=read();m=read();q=read();
	for(int i=1;i<=n;i++)p[i]=read();
	for(int i=1;i<=m;i++){
		int x=read(),y=read();
		edge[i].u=x;edge[i].v=y;edge[i].w=inf;
	}
	for(int i=1;i<=q;i++){
		int op=read(),x=read();
		if(op==1){
			a[++cnt].t=i;a[cnt].x=x;
		}else edge[x].w=i-1;
	}sort(edge+1,edge+m+1,cmp);kruskal();dep[tot]=1;dfs(tot);
	for(int i=1;i<=n;i++)update(1,1,n,dfn[i],p[i]);
	for(int i=1;i<=cnt;i++){
		int now=a[i].x;
		for(int j=19;j>=0;j--)
			if(val[jmp[now][j]]>=a[i].t)now=jmp[now][j];
		int ans=Query(1,1,n,L[now],R[now]);
		printf("%d\n",p[ans]);
		p[ans]=0;update(1,1,n,dfn[ans],p[ans]);
	}return 0;
}

#include <bits/stdc++.h>
#define For(i,a,b) for ( int i=(a);i<=(b);i++ )
#define Dow(i,b,a) for ( int i=(b);i>=(a);i-- )
#define GO(i,x) for ( int i=head[x];i;i=e[i].nex )
#define mem(x,s) memset(x,s,sizeof(x))
#define cpy(x,s) memcpy(x,s,sizeof(x))
#define YES return puts("YES"),0
#define NO return puts("NO"),0
#define GG return puts("-1"),0
#define pb push_back
using namespace std;

struct IO
{
	#define MAXSIZE (1 << 20)
	#define isdigit(x) (x >= '0' && x <= '9')
  	char buf[MAXSIZE],*p1,*p2;
  	char pbuf[MAXSIZE],*pp;
  	IO():p1(buf),p2(buf),pp(pbuf){}
  	inline char gc() {
    	return getchar();
    	if (p1==p2) p2=(p1=buf)+fread(buf,1,MAXSIZE,stdin);
    	return p1==p2?' ':*p1++;
  	}
	inline bool blank(char ch) {return ch==' '||ch =='\n'||ch == '\r'||ch == '\t';}
  	template <class T>
  	inline void read(T &x)
	{
	    register double tmp=1;register bool sign=0; x=0;
	    register char ch=gc();
	    for (;!isdigit(ch);ch=gc()) if(ch=='-') sign=1;
	    for (;isdigit(ch);ch=gc()) x=x*10+(ch-'0');
	    if (ch=='.') for (ch=gc();isdigit(ch);ch=gc()) tmp/=10.0,x+=tmp*(ch-'0');
	    if (sign) x=-x;
  	}
  	inline void read(char *s)
	{
    	register char ch=gc();
		for (;blank(ch);ch=gc());
		for (;!blank(ch);ch=gc()) *s++=ch;
    	*s=0;
  	}
  	inline void read(char &c) {for(c=gc();blank(c);c=gc());}
  	template<class t> inline void write(t x){
		if(x<0) putchar('-'),write(-x);
		else{if(x>9) write(x/10);putchar('0'+x%10);}
	}
} io;

const int mod=1e9+7;
const int mo=998244353;
const int N=2e5+5;

int n,m,T,a[N],col[N],qx[N],qy[N],fa[N],siz[N];
int ux[N],uy[N],del[N],ok[N];
vector<int> g[N];
pair<int,int> Q[N];

inline int find(int x)
{
	if(x==fa[x]) return x;
	return fa[x]=find(fa[x]);
}

inline int Query(int x)
{
//	cout<<"??"<<x<<endl;
//	For(i,0,(int)g[x].size()-1) cout<<g[x][i]<<" "<<col[g[x][i]]<<" "<<ok[g[x][i]]<<endl; puts("");
	while(g[x].size()&&(col[g[x].back()]!=x||ok[g[x].back()])) g[x].pop_back();
	if(g[x].empty()) return 0;
	int ans=g[x].back();
	g[x].pop_back(),ok[ans]=1;
	return ans;
}

int main()
{
	io.read(n),io.read(m),io.read(T);
	For(i,1,n) io.read(a[i]),g[i].pb(a[i]),fa[i]=i,siz[i]=1;
	For(i,1,m) io.read(ux[i]),io.read(uy[i]);
	For(i,1,T)
	{
		int opt,x;
		io.read(opt),io.read(x);
		Q[i]=make_pair(opt,x);
		if(opt==2) del[x]=1;
	}
	For(i,1,m) if(!del[i])
	{
		int fx=find(ux[i]),fy=find(uy[i]);
		if(fx==fy) continue;
		if(siz[fx]>siz[fy]) swap(fx,fy);
		fa[fx]=fy,siz[fy]+=siz[fx];
		For(j,0,(int)g[fx].size()-1) g[fy].pb(g[fx][j]);
	}
	Dow(i,T,1)
	{
		pair<int,int> u=Q[i];
		int op=u.first,x=u.second;
		int fx=find(ux[x]),fy=find(uy[x]);
		if(fx==fy||op==1) continue;
		if(siz[fx]>siz[fy]) swap(fx,fy);
		fa[fx]=fy,siz[fy]+=siz[fx],qx[i]=fx;
		For(j,0,(int)g[fx].size()-1) g[fy].pb(g[fx][j]);
	}
	For(i,1,n) sort(g[i].begin(),g[i].end());
	For(i,1,n) col[a[i]]=find(i);
	For(i,1,T)
	{
		pair<int,int> u=Q[i];
		int op=u.first,x=u.second;
		if(op==1) io.write(Query(find(x))),puts("");
		else if(qx[i])
		{
			For(j,0,g[qx[i]].size()-1) col[g[qx[i]][j]]=qx[i];
			fa[qx[i]]=qx[i];
		}
	}
	return 0;
}

#include <bits/stdc++.h>

using namespace std;

class segtree {
 public:
  struct node {
    int mx = -1;

    void apply(int l, int r, int v) {
      mx = v;
    }
  };

  node unite(const node &a, const node &b) const {
    node res;
    res.mx = max(a.mx, b.mx);
    return res;
  }

  inline void push(int x, int l, int r) {
  }

  inline void pull(int x, int z) {
    tree[x] = unite(tree[x + 1], tree[z]);
  }

  int n;
  vector<node> tree;

  void build(int x, int l, int r) {
    if (l == r) {
      return;
    }
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    build(x + 1, l, y);
    build(z, y + 1, r);
    pull(x, z);
  }

  template <typename M>
  void build(int x, int l, int r, const vector<M> &v) {
    if (l == r) {
      tree[x].apply(l, r, v[l]);
      return;
    }
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    build(x + 1, l, y, v);
    build(z, y + 1, r, v);
    pull(x, z);
  }

  node get(int x, int l, int r, int ll, int rr) {
    if (ll <= l && r <= rr) {
      return tree[x];
    }
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    push(x, l, r);
    node res{};
    if (rr <= y) {
      res = get(x + 1, l, y, ll, rr);
    } else {
      if (ll > y) {
        res = get(z, y + 1, r, ll, rr);
      } else {
        res = unite(get(x + 1, l, y, ll, rr), get(z, y + 1, r, ll, rr));
      }
    }
    pull(x, z);
    return res;
  }

  template <typename... M>
  void modify(int x, int l, int r, int ll, int rr, const M&... v) {
    if (ll <= l && r <= rr) {
      tree[x].apply(l, r, v...);
      return;
    }
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    push(x, l, r);
    if (ll <= y) {
      modify(x + 1, l, y, ll, rr, v...);
    }
    if (rr > y) {
      modify(z, y + 1, r, ll, rr, v...);
    }
    pull(x, z);
  }

  int find_first_knowingly(int x, int l, int r, const function<bool(const node&)> &f) {
    if (l == r) {
      return l;
    }
    push(x, l, r);
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    int res;
    if (f(tree[x + 1])) {
      res = find_first_knowingly(x + 1, l, y, f);
    } else {
      res = find_first_knowingly(z, y + 1, r, f);
    }
    pull(x, z);
    return res;
  }

  int find_first(int x, int l, int r, int ll, int rr, const function<bool(const node&)> &f) {
    if (ll <= l && r <= rr) {
      if (!f(tree[x])) {
        return -1;
      }
      return find_first_knowingly(x, l, r, f);
    }
    push(x, l, r);
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    int res = -1;
    if (ll <= y) {
      res = find_first(x + 1, l, y, ll, rr, f);
    }
    if (rr > y && res == -1) {
      res = find_first(z, y + 1, r, ll, rr, f);
    }
    pull(x, z);
    return res;
  }

  int find_last_knowingly(int x, int l, int r, const function<bool(const node&)> &f) {
    if (l == r) {
      return l;
    }
    push(x, l, r);
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    int res;
    if (f(tree[z])) {
      res = find_last_knowingly(z, y + 1, r, f);
    } else {
      res = find_last_knowingly(x + 1, l, y, f);
    }
    pull(x, z);
    return res;
  }

  int find_last(int x, int l, int r, int ll, int rr, const function<bool(const node&)> &f) {
    if (ll <= l && r <= rr) {
      if (!f(tree[x])) {
        return -1;
      }
      return find_last_knowingly(x, l, r, f);
    }
    push(x, l, r);
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    int res = -1;
    if (rr > y) {
      res = find_last(z, y + 1, r, ll, rr, f);
    }
    if (ll <= y && res == -1) {
      res = find_last(x + 1, l, y, ll, rr, f);
    }
    pull(x, z);
    return res;
  }

  segtree(int _n) : n(_n) {
    assert(n > 0);
    tree.resize(2 * n - 1);
    build(0, 0, n - 1);
  }

  template <typename M>
  segtree(const vector<M> &v) {
    n = v.size();
    assert(n > 0);
    tree.resize(2 * n - 1);
    build(0, 0, n - 1, v);
  }

  node get(int ll, int rr) {
    assert(0 <= ll && ll <= rr && rr <= n - 1);
    return get(0, 0, n - 1, ll, rr);
  }

  node get(int p) {
    assert(0 <= p && p <= n - 1);
    return get(0, 0, n - 1, p, p);
  }

  template <typename... M>
  void modify(int ll, int rr, const M&... v) {
    assert(0 <= ll && ll <= rr && rr <= n - 1);
    modify(0, 0, n - 1, ll, rr, v...);
  }

  // find_first and find_last call all FALSE elements
  // to the left (right) of the sought position exactly once

  int find_first(int ll, int rr, const function<bool(const node&)> &f) {
    assert(0 <= ll && ll <= rr && rr <= n - 1);
    return find_first(0, 0, n - 1, ll, rr, f);
  }

  int find_last(int ll, int rr, const function<bool(const node&)> &f) {
    assert(0 <= ll && ll <= rr && rr <= n - 1);
    return find_last(0, 0, n - 1, ll, rr, f);
  }
};

class dsu {
 public:
  vector<int> p;
  int n;

  dsu(int _n) : n(_n) {
    p.resize(n);
    iota(p.begin(), p.end(), 0);
  }

  inline int get(int x) {
    return (x == p[x] ? x : (p[x] = get(p[x])));
  }

  inline bool unite(int x, int y) {
    x = get(x);
    y = get(y);
    if (x != y) {
      p[x] = y;
      return true;
    }
    return false;
  }
};

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int n, m, q;
  cin >> n >> m >> q;
  vector<int> p(n);
  vector<int> pos(n);
  for (int i = 0; i < n; i++) {
    cin >> p[i];
    --p[i];
    pos[p[i]] = i;
  }
  vector<int> from(m);
  vector<int> to(m);
  for (int i = 0; i < m; i++) {
    cin >> from[i] >> to[i];
    --from[i]; --to[i];
  }
  vector<int> op(q);
  vector<int> id(q);
  for (int i = 0; i < q; i++) {
    cin >> op[i] >> id[i];
    --id[i];
  }
  vector<bool> removed(m, false);
  for (int i = 0; i < q; i++) {
    if (op[i] == 2) {
      removed[id[i]] = true;
    }
  }
  dsu d(n);
  vector<int> head(n);
  vector<int> tail(n);
  iota(head.begin(), head.end(), 0);
  iota(tail.begin(), tail.end(), 0);
  vector<int> nxt(n, -1);
  for (int i = 0; i < m; i++) {
    if (!removed[i]) {
      int x = d.get(from[i]);
      int y = d.get(to[i]);
      if (x != y) {
        d.unite(x, y);
        nxt[tail[x]] = head[y];
        head[y] = head[x];
      }
    }
  }
  vector<int> start(q, -1);
  vector<int> finish(q, -1);
  for (int i = q - 1; i >= 0; i--) {
    if (op[i] == 2) {
      int x = d.get(from[id[i]]);
      int y = d.get(to[id[i]]);
      if (x != y) {
        d.unite(x, y);
        nxt[tail[x]] = head[y];
        head[y] = head[x];
      }
    } else {
      int x = d.get(id[i]);
      start[i] = head[x];
      finish[i] = tail[x];
    }
  }
  vector<int> seq;
  for (int i = 0; i < n; i++) {
    if (d.get(i) == i) {
      int u = head[i];
      while (true) {
        seq.push_back(u);
        if (u == tail[i]) {
          break;
        }
        u = nxt[u];
      }
    }
  }
  assert((int) seq.size() == n);
  vector<int> in_seq(n, -1);
  for (int i = 0; i < n; i++) {
    in_seq[seq[i]] = i;
  }
  vector<int> arr(n);
  for (int i = 0; i < n; i++) {
    arr[i] = p[seq[i]];
  }
  segtree st(arr);
  for (int i = 0; i < q; i++) {
    if (op[i] == 1) {
      int L = in_seq[start[i]];
      int R = in_seq[finish[i]];
      int res = st.get(L, R).mx;
      cout << res + 1 << '\n';
      if (res != -1) {
        st.modify(pos[res], pos[res], -1);
      }
    }
  }
  return 0;
}

#include <bits/stdc++.h>
#include <random>

using namespace std;

typedef unsigned long long ull;
typedef long long ll;
typedef long double ld;
//#define int ll
typedef vector<char> vc;
typedef vector<vc> vvc;
typedef vector<vvc> vvvc;
typedef pair<int, int> pii;
typedef pair<pii, pii> piii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector< vi > vvi;
typedef vector< vvi > vvvi;
typedef vector<short> vs;
typedef vector<vs> vvs;
typedef vector<vvs> vvvs;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<vvl> vvvl;
typedef vector<ld> vld;
typedef vector<vld> vvld;
typedef vector<vvld> vvvld;
typedef vector<string> vst;
typedef vector<vst> vvst;
typedef pair<ld, ld> pld;

#define inmin(a, b) a = min(a, (b))
#define inmax(a, b) a = max(a, (b))
#define ALL(a) a.begin(),a.end()
#define RALL(a) a.rbegin(),a.rend()
#define sqr(x) ((x) * (x))
#define fori(i, n) for(int i = 0; i < int(n); ++i)
#define SZ(a) ((int)((a).size()))
#define triple(T) tuple<T, T, T>
#define quad(T) tuple<T, T, T, T>
#define watch(x) cerr << (#x) << " = " << (x) << endl;

#ifdef RUS_HOME
#define cerr cout
#else
#define cerr if (false) cerr
#endif

const double PI = 2 * acos(0.0);
#define rand shittttty_shit
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
mt19937_64 rng_64(chrono::steady_clock::now().time_since_epoch().count());

const string DIGITS = "0123456789";
const string ALPH = "abcdefghijklmnopqrstuvwxyz";

template <class T0, class T1>
inline ostream & operator << (ostream &out, pair<T0, T1> &a) {
    return out << "{" << a.first << ", " << a.second << "}";
}

template <class T0, class T1>
inline istream & operator >> (istream &in, pair<T0, T1> &a) {
    return in >> a.first >> a.second;
}

template <class T0, class T1, class T2>
inline ostream & operator << (ostream &out, tuple<T0, T1, T2> &a) {
    return out << "{" << get<0>(a) << ", " << get<1>(a) << ", " << get<2>(a) << "}";
}

template <class T0, class T1, class T2, class T3>
inline ostream & operator << (ostream &out, tuple<T0, T1, T2, T3> &a) {
    return out << "{" << get<0>(a) << ", " << get<1>(a) << ", " << get<2>(a) << ", " <<  get<3>(a) << "}";
}

template<class T>
inline ostream & operator << (ostream &out, vector<T> &a) {
    out << "[";
    fori (i, a.size())
        out << a[i] << vector<string>{", ", "]  "}[i + 1 == a.size()];
    return out;
}

void smain();

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
#ifdef RUS_HOME
    freopen("input", "r", stdin);
    //freopen("output.txt", "w", stdout);
    clock_t start = clock();
#else
    //("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
#endif
    cout << setprecision(12) << fixed;
    smain();
#ifdef RUS_HOME
    cout << "\n\n\n\nTOTAL EXECUTION TIME: " << float( clock () - start ) /  CLOCKS_PER_SEC << endl;
#endif
    return 0;
}

const int MOD=1e9+7,N=2e5+100,oo=1e18+10,A=26,M=3e5+100,K=5e5+100;

set<int>g[N];
int p[N];
pii edges[M];
pii q[K];
int ans[K],lst[K];

int par[N],sz[N];
vi f[N];
vi kek[N];
map<int,int>st[N];
bool used[N];

int merge(int v,int u){
    v=par[v];
    u=par[u];
    if(v==u)
        return 0;
    int fl=0;
    if(sz[v]<sz[u]){
        swap(v,u);
        fl=1;
    }
    for(int i=0;i<SZ(f[u]);i++){
        int y=f[u][i];
        par[y]=v;
        kek[y].push_back(v);
        f[v].push_back(y);
        st[v][p[y]]=y;
    }
    sz[v]+=sz[u];
    return fl;
}

void antimerge(int v,int u){
    if(v==u)
        return;
    for(int i=0;i<SZ(f[u]);i++){
        int y=f[u][i];
        par[y]=u;
        if(!used[y])
            st[v].erase(p[y]);
    }
}

void rec(int nm){
    if(!nm)
        return;
    int ed=q[nm].second;
    int u=par[edges[ed].first],v=par[edges[ed].second];
    int fl=merge(u,v);
    if(fl)
        swap(u,v);
    int h=lst[nm];
    rec(h);
    for(int i=h+1;i<nm;i++){
        int a=par[q[i].second];
        while(SZ(st[a])){
            auto it=st[a].end(); it--;
            if(used[(*it).second])
                st[a].erase(it);
            else{
                int y=(*it).second;
                ans[i]=p[y];
                used[y]=true;
                break;
            }
        }
    }
    antimerge(u,v);
}

void smain() {

    int n,m,k;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        cin>>p[i];
    }
    for(int i=1;i<=m;i++){
        int a,b;
        cin>>a>>b;
        g[a].insert(b);
        g[b].insert(a);
        edges[i]={a,b};
    }

    for(int i=1;i<=k;i++){
        int a,b;
        cin>>a>>b;
        q[i]={a,b};
        if(a==2){
            int u=edges[b].first,v=edges[b].second;
            g[u].erase(v);
            g[v].erase(u);
        }
    }

    for(int i=1;i<=n;i++){
        par[i]=i;
        sz[i]=1;
        f[i]={i};
        kek[i]={i};
        st[i][p[i]]=i;
    }

    for(int i=1;i<=n;i++){
        for(auto u:g[i]){
            merge(i,u);
        }
    }
    edges[m+1]={1,1};
    q[k+1]={2,m+1};
    q[0]={2,m+1};
    for(int i=1;i<=k;i++){
        if(q[i-1].first==2)
            lst[i]=i-1;
        else
            lst[i]=lst[i-1];
    }
    rec(k+1);

    for(int i=1;i<=k;i++){
        if(q[i].first==1){
            cout<<ans[i]<<"\n";
        }
    }

}

/**
 *    author:  tourist
 *    created: 09.05.1945 00:43:00
**/
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#define fi first
#define se second
#define pb emplace_back
#define all(x) x.begin(),x.end()
#define re return
#define mp make_pair
#define sz(x) ((int)(x).size())
#define rep(i, n) for (int i = 0; i < (n); i++)
#define rrep(i, n) for (int i = (n) - 1; i >= 0; i--)
#define unq(x) (x.resize(unique(all(x)) - x.begin()))
#define sqr(x) ((x)*(x))
#define int long long

using namespace std;
using namespace __gnu_pbds;

typedef tree <int, null_type, less <int>, rb_tree_tag, tree_order_statistics_node_update> indexed_set;

typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int, int> ii;
typedef vector<ii> vii;
typedef vector<string> vs;
typedef pair<ll, ll> pll;
typedef vector<ll> vll;
typedef pair<double, double> pdd;
typedef double D;

double getTime() { return clock() / (double) CLOCKS_PER_SEC;};

const int mod = 1e9 + 7;
const ll INF = 3e18;
const int N = 2e5 + 5;
const int P0 = 437;
const int P1 = 343;
const int d = 400;

vi start(N), was(N), pa(N), Sz(N);
vii v[N];
int timer = 1;
set <int> group[N];
vi st_g[N];

void Make(int i)
{
    pa[i] = i;
    Sz[i] = 1;
}

int Find (int pos)
{
    if(pa[pos] != pos)
        pa[pos] = Find(pa[pos]);
    re pa[pos];
}

vi from, to;
vvi g;

vi lol;

void Union(int i, int j)
{
    int i_ind = Find(i), j_ind = Find(j);
    if(i_ind == j_ind)
    {
        from.pb(-1);
        to.pb(-1);
        g.pb(lol);
        re;
    }
    if(Sz[i_ind] <= Sz[j_ind])
    {
        pa[i_ind] = j_ind;
        Sz[j_ind] += Sz[i_ind];
        from.pb(j_ind);
        to.pb(i_ind);
        g.pb(st_g[i_ind]);
        for (int x : st_g[i_ind])
            st_g[j_ind].pb(x);
    }
    else
    {
        pa[j_ind] = i_ind;
        Sz[i_ind] += Sz[j_ind];
        from.pb(i_ind);
        to.pb(j_ind);
        g.pb(st_g[j_ind]);
        for (int x : st_g[j_ind])
            st_g[i_ind].pb(x);
    }
}

void dfs (int pos)
{
    was[pos] = timer;
    Sz[timer]++;
    for (auto u : v[pos])
    {
        int x = u.fi, i = u.se;
        if(!was[x] && start[i])
            dfs(x);
    }
}

void solve()
{
    int n, m, k;
    cin >> n >> m >> k;
    vi p(n);
    rep(i, n)
        cin >> p[i];
    vi L(m), R(m);
    start.resize(n);
    rep(i, m)
    {
        start[i] = 1;
        int l, r;
        cin >> l >> r;
        l--; r--;
        L[i] = l; R[i] = r;
        v[l].pb(r, i);
        v[r].pb(l, i);
    }
    vi t(k), a(k);
    rep(i, k)
    {
        cin >> t[i] >> a[i];
        a[i]--;
        if(t[i] == 2)
            start[a[i]] = 0;
    }
    rep(i, n)
    {
        if(!was[i])
        {
            dfs(i);
            timer++;
        }
//        cout << was[i] << ' ';
    }
//    cout << '\n';
    vi Was(n + 1, -1);
    rep(i, n)
    {
        if(Was[was[i]] == -1)
        {
            Was[was[i]] = i;
            Make(i);
            st_g[i].pb(i);
        }
        else
        {
            Make(i);
            st_g[i].pb(i);
            Union(Was[was[i]], i);
        }
    }

    from.clear();
    to.clear();
    g.clear();

    rrep(i, k)
    {
        if(t[i] == 1)
            continue;
        Union(L[a[i]], R[a[i]]);
    }

    reverse(all(from));
    reverse(all(to));
    reverse(all(g));

    vi now(n);

    rep(i, n)
    {
        int ind = Find(i);
        group[ind].insert(p[i]);
        now[i] = ind;
//        cout << now[i] << ' ';
    }

    int pos = 0;

    rep(i, k)
    {
        if(t[i] == 1)
        {
            auto it = group[now[a[i]]].end();
            it--;
            cout << *it << '\n';
            group[now[a[i]]].erase(it);
            group[now[a[i]]].insert(0);
        }
        else
        {
            if(from[pos] != -1)
                for (int x : g[pos])
                {
                    group[from[pos]].erase(p[x]);
                    group[to[pos]].insert(p[x]);
                    now[x] = to[pos];
                }
            pos++;
        }
    }
    re;

}

signed main()
{
    //freopen("input.txt ", "r", stdin);
    //freopen("output.txt", "w", stdout);
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int qq = 1;
//    cin >> qq;
    while(qq--)
        solve();
}

#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
const int N = 5e5 + 3;
const int M = 3e5 + 4;
const int QU = 5e5 + 3;
typedef pair < int, int > ii;
int n, m, q;
int val[N];
ii edge[M];
ii qu[QU];
bool kt[M];
int cha[N], rnk[N];
int init;
int tin[N], tout[N];
vector < int > adj[N];

int findcha(int u)
{
    if (cha[u] != u) return cha[u] = findcha(cha[u]);

    return cha[u];
}

bool join(int u, int v)
{
    u = findcha(u);
    v = findcha(v);

    if (u == v) return false;

    n++;
    cha[u] = n;
    cha[v] = n;
    cha[n] = n;
    adj[n].push_back(u);
    adj[n].push_back(v);

    return true;
}

int dem = 0;

void dfs(int i, int j)
{
    dem++;
    tin[i] = dem;

    for (int u : adj[i])
    {
        if (u == j) continue;

        dfs(u, i);
    }

    tout[i] = dem;
}

struct ok
{
    int lo;
    int hi;
    int val;
    int pos;
};
ok Node[4 * N];

void build(int id, int l, int r)
{
    Node[id].lo = l; Node[id].hi = r;

    if (l == r) return;

    int mid = (l + r) / 2;

    build(id * 2, l, mid);
    build(id * 2 + 1, mid + 1, r);
}

void update(int id, int pos, int val)
{
    if (Node[id].lo > pos || Node[id].hi < pos) return;

    if (Node[id].lo == Node[id].hi)
    {
        Node[id].val = val;
        Node[id].pos = pos;

        return;
    }

    update(id * 2, pos, val);
    update(id * 2 + 1, pos, val);

    Node[id].val = max(Node[id * 2].val, Node[id * 2 + 1].val);

    if (Node[id * 2].val > Node[id * 2 + 1].val)
        Node[id].pos = Node[id * 2].pos;
    else
        Node[id].pos = Node[id * 2 + 1].pos;
}

ii getma(int id, int l, int r)
{
    if (Node[id].lo > r || Node[id].hi < l) return {0, 0};

    if (l <= Node[id].lo && Node[id].hi <= r)
        return {Node[id].val, Node[id].pos};

    return max(getma(id * 2, l, r), getma(id * 2 + 1, l, r));
}

int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    //freopen("t.inp","r",stdin); freopen("t.out","w",stdout);

    cin >> n >> m >> q;

    for (int i = 1; i <= n; i++)
        cin >> val[i];

    memset(kt, true, sizeof kt);

    for (int i = 1; i <= m; i++)
        cin >> edge[i].fi >> edge[i].se;

    for (int i = 1; i <= q; i++)
    {
        cin >> qu[i].first >> qu[i].second;

        if (qu[i].first == 2) kt[qu[i].second] = false;
    }

    for (int i = 1; i <= n; i++)
        cha[i] = i;

    init = n;

    for (int i = 1; i <= m; i++)
    {
        if (!kt[i]) continue;

        join(edge[i].fi, edge[i].se);
    }

    for (int i = q; i > 0; i--)
    {
        if (qu[i].first == 2)
        {
            int id = qu[i].second;

            join(edge[id].fi, edge[id].se);
        }
        else
        {
            qu[i].second = findcha(qu[i].second);
        }
    }

    dfs(n, 0);

    build(1, 1, dem);

    for (int i = 1; i <= init; i++)
        update(1, tin[i], val[i]);

    for (int i = 1; i <= q; i++)
    {
        if (qu[i].first == 1)
        {
            ii top = getma(1, tin[qu[i].second], tout[qu[i].second]);

            cout << top.first << '\n';

            update(1, top.second, 0);
        }
    }
}

/**
 ____ ____ ____ ____ ____
||a |||t |||o |||d |||o ||
||__|||__|||__|||__|||__||
|/__\|/__\|/__\|/__\|/__\|

**/

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N_MAX = 200002;
const int M_MAX = 300002;
const int Q_MAX = 500002;

int n, m, q;

int p[N_MAX];

struct Edge
{
    int u, v;
};

Edge edges[M_MAX];

struct Query
{
    int type;
    int x;
};

Query queries[Q_MAX];

int aux[Q_MAX];

int root[N_MAX + Q_MAX];

int leftSon[N_MAX + Q_MAX], rightSon[N_MAX + Q_MAX];

int findRoot (int u)
{
    if(root[u] == u)
        return u;
    return root[u] = findRoot(root[u]);
}

int cntNodes;

void join (int u, int v)
{
    u = findRoot(u);
    v = findRoot(v);
    if(u == v)
        return;
    cntNodes++;
    leftSon[cntNodes] = u;
    rightSon[cntNodes] = v;
    root[u] = root[v] = cntNodes;
    root[cntNodes] = cntNodes;
}

int L[N_MAX + Q_MAX], R[N_MAX + Q_MAX];

int label[N_MAX + Q_MAX];
int inv[N_MAX + Q_MAX];

int curr;

void dfs (int u)
{
    inv[++curr] = u;
    label[u] = curr;
    L[u] = R[u] = label[u];
    if(leftSon[u] != 0)
    {
        dfs(leftSon[u]);
        L[u] = L[leftSon[u]];
    }
    if(rightSon[u] != 0)
    {
        dfs(rightSon[u]);
        R[u] = R[rightSon[u]];
    }
}

int SGT[(N_MAX + Q_MAX) * 4];

int SGTjoin (int a, int b)
{
    if(p[inv[a]] > p[inv[b]])
        return a;
    else
        return b;
}

void SGTbuild (int node, int l, int r)
{
    if(l == r)
    {
        SGT[node] = l;
        return;
    }
    int mid = ((l + r) >> 1), lSon = (node << 1), rSon = (lSon | 1);
    SGTbuild(lSon, l, mid);
    SGTbuild(rSon, mid + 1, r);
    SGT[node] = SGTjoin(SGT[lSon], SGT[rSon]);
}

void SGTupdate (int node, int l, int r, int upos)
{
    if(l == r)
    {
        p[inv[l]] = 0;
        return;
    }
    int mid = ((l + r) >> 1), lSon = (node << 1), rSon = (lSon | 1);
    if(upos <= mid)
        SGTupdate(lSon, l, mid, upos);
    else
        SGTupdate(rSon, mid + 1, r, upos);
    SGT[node] = SGTjoin(SGT[lSon], SGT[rSon]);
}

int SGTquery (int node, int l, int r, int ql, int qr)
{
    if(ql <= l && r <= qr)
        return SGT[node];
    int mid = ((l + r) >> 1), lSon = (node << 1), rSon = (lSon | 1);
    if(ql <= mid && mid + 1 <= qr)
        return SGTjoin(SGTquery(lSon, l, mid, ql, qr), SGTquery(rSon, mid + 1, r, ql, qr));
    else if(ql <= mid)
        return SGTquery(lSon, l, mid, ql, qr);
    else
        return SGTquery(rSon, mid + 1, r, ql, qr);
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m >> q;
    for(int i = 1; i <= n; i++)
        cin >> p[i];
    for(int i = 1; i <= m; i++)
        cin >> edges[i].u >> edges[i].v;
    for(int i = 1; i <= q; i++)
        cin >> queries[i].type >> queries[i].x;
    for(int i = 1; i <= n; i++)
        root[i] = i;
    cntNodes = n;
    for(int i = q; i >= 1; i--)
        if(queries[i].type == 1)
            aux[i] = findRoot(queries[i].x);
        else
            join(edges[queries[i].x].u, edges[queries[i].x].v);
    cout << "*\n";
    dfs(root[1]);
    SGTbuild(1, 1, cntNodes);
    for(int i = 1; i <= q; i++)
        if(queries[i].type == 1)
        {
            int pos = SGTquery(1, 1, cntNodes, L[aux[i]], R[aux[i]]);
            cout << p[inv[pos]] << "\n";
            SGTupdate(1, 1, cntNodes, pos);
        }
    return 0;
}

#include <bits/stdc++.h>

using namespace std;
#define sim template < class c
#define ris return * this
#define dor > debug & operator <<
#define eni(x) sim > typename \
  enable_if<sizeof dud<c>(0) x 1, debug&>::type operator<<(c i) {
sim > struct rge { c b, e; };
sim > rge<c> range(c i, c j) { return rge<c>{i, j}; }
sim > auto dud(c* x) -> decltype(cerr << *x, 0);
sim > char dud(...);
struct debug {
#ifndef LOCAL
~debug() { cerr << endl; }
eni(!=) cerr << boolalpha << i; ris; }
eni(==) ris << range(begin(i), end(i)); }
sim, class b dor(pair < b, c > d) {
  ris << "(" << d.first << ", " << d.second << ")";
}
sim dor(rge<c> d) {
  *this << "[";
  for (auto it = d.b; it != d.e; ++it)
	*this << ", " + 2 * (it == d.b) << *it;
  ris << "]";
}
#else
sim dor(const c&) { ris; }
#endif
};
#define imie(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef pair<long long, int> pli;
typedef long long ll;
#define f first
#define s second
#define endl '\n'
#define all(x) x.begin(),x.end()
const int N=5e5+1;
int p[ N ],tin [ N ],tout[ N ],timer=0;
int get( int v ){
    return p[v] = ( v == p[v] ? v : get( p[ v ] ) );
}
int n,m,q;
vector<int> g [ N ];
pii t[ 4 * N ];
int a[ N ];
int obr[N];
void mg(int a, int b){
    int c = get( a ), d = get( b );
    n++;
    p[c]=n;
    p[d]=n;
    g[ n ].emplace_back(c);
    g[ n ].emplace_back(d);
    return ;
}
void dfs(int v, int p){
    tin[ v ] = ++timer;
    obr[ timer ] = v;
    for(auto &z : g[ v ]){
        dfs( z, v );
    }
    tout[ v ] = timer;
}
void b_tr(int v,int tl,int tr){
    if(tl == tr){
        t[v]={a[obr[tl]],tl};
    }
    else{
        int tm=(tl+tr)>>1;
        b_tr(2*v,tl,tm);
        b_tr(2*v+1,tm+1,tr);
        t[v]=max(t[2*v],t[2*v+1]);
    }
}
pii getMax(int l,int r,int v,int tl,int tr){
    if(tl>=l && tr<=r){
        return t[v];
    }
    if(tl>r || tr<l) return {0,n};
    int tm=(tl+tr)>>1;
    return max(getMax(l,r,2*v,tl,tm),getMax(l,r,2*v+1,tm+1,tr));
}
void upd(int id,int v,int tl,int tr){
    if(tl==tr){
        t[v].first=0;
        return ;
    }
    int tm=(tl+tr)>>1;
    if(tm>=id)
        upd(id,2*v,tl,tm);
    else
        upd(id,2*v+1,tm+1,tr);
    t[v]=max(t[2*v],t[2*v+1]);
}
pii e[N];
bool ex[N];
pii qe[N];
signed main(){
    cin.tie(0);cout.tie(0);ios_base::sync_with_stdio(false);
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i = 0;i < m;i++){
        int v,u;
        cin>>v>>u;
        e[i]={v,u};
    }
    iota(p,p+N,0);
    for(int i = 0;i < q;i++){
        int tp;
        cin>>tp;
        int id;
        cin>>id;
        if(tp==2){
            ex[id-1]=1;
        }
        qe[i]={tp,id};
    }
    for(int i = 0; i < m;i++){
        if(!ex[i]){
            mg(e[i].f,e[i].s);
        }
    }
    for(int i = q - 1; ~ i; --i){
        if(qe[i].f==2)
            mg(e[qe[i].s-1].f,e[qe[i].s-1].s);
        else {
            qe[i].s=get(qe[i].s);
        }
    }
    for(int i = 1;i <= n; i++){
        if(get(i)==i)
            dfs(i,i);
    }
    b_tr(1,1,n);
    for(int i = 0; i<q; i++){
        if(qe[i].f==1){
            int id=qe[i].s;
            auto w=getMax(tin[id],tout[id],1,1,n);
            upd(w.s,1,1,n);
            cout<<w.f<<endl;
        }
    }
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
inline int rd(int f = 1, int x = 0, char ch = ' ')
{
    while(!isdigit(ch = getchar())) if(ch == '-') f = -1;
    while(isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    return f*x;
}
const int N = 5e5+5, L = 20;
int n, m, q, tot, tk, o[N], b[N], t[N<<2], ls[N], rs[N], pos[N], rk[N], ac[N][L], w[N], u[N], v[N], a[N], fa[N], lp[N], rp[N], vis[N];
int fd(int x) { return x == fa[x]?x:fa[x] = fd(fa[x]); }
int chkmax(int x, int y) { return a[x]>a[y]?x:y; }
void pu(int x) { t[x] = chkmax(t[x<<1], t[x<<1|1]); }
void init(int x, int l, int r)
{
    if(l == r) return t[x] = rk[l], void(); int mid = (l+r)>>1;
    init(x<<1, l, mid), init(x<<1|1, mid+1, r), pu(x);
}
void del(int x, int l, int r, int p)
{
    if(l == r) return a[t[x]] = 0, void(); int mid = (l+r)>>1;
    if(p <= mid) del(x<<1, l, mid, p); else del(x<<1|1, mid+1, r, p); pu(x);
}
int ask(int x, int l, int r, int ql, int qr)
{
    if(ql <= l&&r <= qr) return t[x]; int mid = (l+r)>>1, ret = 0;
    if(ql <= mid) ret = chkmax(ret, ask(x<<1, l, mid, ql, qr));
    if(qr > mid) ret = chkmax(ret, ask(x<<1|1, mid+1, r, ql, qr));
    return ret;
}
void lk(int k, int t)
{
    int x = fd(u[k]), y = fd(v[k]); if(x == y) return;
    ++tot, w[tot] = t, fa[tot] = fa[x] = fa[y] = tot, ls[tot] = x, rs[tot] = y;
}
void dfs(int x)
{
    assert(w[x] >= w[ac[x][0]]);
    if(!ls[x]&&!rs[x]) return rk[lp[x] = rp[x] = pos[x] = ++tk] = x, void();
    ac[ls[x]][0] = ac[rs[x]][0] = x;
    for(int i = 0; i+1 < L; ++i) ac[ls[x]][i+1] = ac[rs[x]][i+1] = ac[ac[x][i]][i];
    dfs(ls[x]), dfs(rs[x]), lp[x] = lp[ls[x]], rp[x] = rp[rs[x]];
}
int get(int x, int t)
{
    for(int i = L-1; ~i; --i) if(ac[x][i]&&w[ac[x][i]] > t) x = ac[x][i];
    return x;
}
int main()
{
    n = rd(), m = rd(), q = rd(), tot = n;
    for(int i = 1; i <= n; ++i) a[i] = rd(), fa[i]  = i, w[i] = q+1;
    for(int i = 1; i <= m; ++i) u[i] = rd(), v[i] = rd();
    for(int i = 1; i <= q; ++i) o[i] = rd(), b[i] = rd(), vis[b[i]] |= o[i]-1;
    for(int i = 1; i <= m; ++i) if(!vis[i]) lk(i, q+1);
    for(int i = q; i; --i) if(o[i] == 2) lk(b[i], i);
    for(int i = 1; i <= tot; ++i) if(fa[i] == i) dfs(i);
    init(1, 1, n), assert(tk == n);
    for(int i = 1; i <= q; ++i) if(o[i] == 1)
    {
        int e = get(b[i], i), k = ask(1, 1, n, lp[e], rp[e]);
        printf("%d\n", a[k]),  assert(k), del(1, 1, n, pos[k]);
    }
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
inline int rd(int f = 1, int x = 0, char ch = ' ')
{
    while(!isdigit(ch = getchar())) if(ch == '-') f = -1;
    while(isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    return f*x;
}
const int N = 5e5+5, L = 20;
int n, m, q, tot, tk, o[N], b[N], t[N<<2], ls[N], rs[N], pos[N], rk[N], ac[N][L], w[N], u[N], v[N], a[N], fa[N], lp[N], rp[N], vis[N];
int fd(int x) { return x == fa[x]?x:fa[x] = fd(fa[x]); }
int chkmax(int x, int y) { return a[x]>a[y]?x:y; }
void pu(int x) { t[x] = chkmax(t[x<<1], t[x<<1|1]); }
void init(int x, int l, int r)
{
    if(l == r) return t[x] = rk[l], void(); int mid = (l+r)>>1;
    init(x<<1, l, mid), init(x<<1|1, mid+1, r), pu(x);
}
void del(int x, int l, int r, int p)
{
    if(l == r) return a[t[x]] = 0, void(); int mid = (l+r)>>1;
    if(p <= mid) del(x<<1, l, mid, p); else del(x<<1|1, mid+1, r, p); pu(x);
}
int ask(int x, int l, int r, int ql, int qr)
{
    if(ql <= l&&r <= qr) return t[x]; int mid = (l+r)>>1, ret = 0;
    if(ql <= mid) ret = chkmax(ret, ask(x<<1, l, mid, ql, qr));
    if(qr > mid) ret = chkmax(ret, ask(x<<1|1, mid+1, r, ql, qr));
    return ret;
}
void lk(int k, int t)
{
    int x = fd(u[k]), y = fd(v[k]); if(x == y) return;
    ++tot, w[tot] = t, fa[tot] = fa[x] = fa[y] = tot, ls[tot] = x, rs[tot] = y;
}
void dfs(int x)
{
    assert(w[x] >= w[ac[x][0]]);
    if(!ls[x]&&!rs[x]) return rk[lp[x] = rp[x] = pos[x] = ++tk] = x, void();
    ac[ls[x]][0] = ac[rs[x]][0] = x;
    for(int i = 0; i+1 < L; ++i) ac[ls[x]][i+1] = ac[rs[x]][i+1] = ac[ac[x][i]][i];
    dfs(ls[x]), dfs(rs[x]), lp[x] = lp[ls[x]], rp[x] = rp[rs[x]];
}
int get(int x, int t)
{
    // for(int i = L-1; ~i; --i) if(w[ac[x][i]] > t) x = ac[x][i];
    for( ; ac[x][0]&&ac[x][0] > t; x = ac[x][0]);
    return x;
}
int main()
{
    n = rd(), m = rd(), q = rd(), tot = n;
    for(int i = 1; i <= n; ++i) a[i] = rd(), fa[i]  = i, w[i] = q+1;
    for(int i = 1; i <= m; ++i) u[i] = rd(), v[i] = rd();
    for(int i = 1; i <= q; ++i) o[i] = rd(), b[i] = rd(), vis[b[i]] |= o[i]-1;
    for(int i = 1; i <= m; ++i) if(!vis[i]) lk(i, q+1);
    for(int i = q; i; --i) if(o[i] == 2) lk(b[i], i);
    for(int i = 1; i <= tot; ++i) if(fa[i] == i) dfs(i);
    init(1, 1, n), assert(tk == n);
    for(int i = 1; i <= q; ++i) if(o[i] == 1)
    {
        int e = get(b[i], i), k = ask(1, 1, n, lp[e], rp[e]);
        printf("%d\n", a[k]),  assert(k), del(1, 1, n, pos[k]);
    }
    return 0;
}

#define _USE_MATH_DEFINES
//#pragma GCC optimize("O3")
// #pragma GCC target("sse4")

#include <bits/stdc++.h>
using namespace std;

#define LSB(i) ((i) & -(i)) // zeroes all the bits except the least significant one

#define OPEN(a) freopen(a, "r", stdin)
#define F first
#define S second
#define PB push_back
#define BOOST ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define ALL(i) begin((i)), end((i))
#define SZ(i) ((int)i.size())
#define SORT(a) sort(ALL(a))

using LL = long long;
using LD = long double;//__float128;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
using PLD = pair<LD, LD>;
using VI = vector<int>;
using VLL = vector<LL>;
using VLD = vector<LD>;
using VPII = vector<PII>;
using VPLL = vector<PLL>;
using VPLD = vector<PLD>;
using VVI = vector<VI>;

#define GET_MACRO(_1, _2, _3, _4, NAME, ...) NAME
#define __FOR3(i, a, n, inc) for(int i = (a); (inc) > 0 ? i < (n) : i >= (n); i += (inc))
#define __FOR2(i, a, n) __FOR3(i, a, n, 1)
#define __FOR1(i, n) __FOR2(i, 0, n)
#define FOR(...) GET_MACRO(__VA_ARGS__, __FOR3, __FOR2, __FOR1)(__VA_ARGS__)

#define REV(a,b) for(int a= b; a >= 0; --a)
#define FRU(a,b) for(const auto& a: b)
#define FRUM(a,b) for(auto& a : b)

const int inf = 1e9 + 7;
const int MOD = 998244353;
const LL INF = 1e18 + 7;
const long double PI = acos(-1);
const LD EPS = 1e-9;

namespace input {
    template< class T> istream& operator>>(istream& st, vector<T> & container) { for (auto& u : container) st >> u; return st; }
    template< class T, size_t N> istream& operator>>(istream& st, array<T, N> & container) { for (auto& u : container) st >> u; return st; }
    template <class T, class U> istream& operator>>(istream& st, pair<T, U> & p) { st >> p.first >> p.second; return st; }

    void re() {}
    template<typename T, typename... TArgs> void re(T& x, TArgs&... rest) { cin >> x; re(rest...); }
}
using namespace input;

namespace output
{
    template< class T> ostream& operator<<(ostream& st, const vector<T> & container) { for (auto& u : container) st << u << ' '; return st; }
    template< class T, size_t N> ostream& operator<<(ostream& st, const array<T, N> & container) { for (auto& u : container) st << u << ' '; return st; }
    template <class T, class U> ostream& operator<<(ostream& st, pair<T, U> p) { st << p.first << ' ' << p.second; return st; }

    void pr() {}
    template <typename T> void pr(const T& x) { cout << x; }
    template <typename T, typename... TArgs> void pr(const T& x, const TArgs&... rest) { cout << x << ' '; pr(rest...); }
    template <typename... TArgs> void prln(const TArgs&... args) { pr(args...); cout << '\n'; }
}
using namespace output;

namespace pairs
{
    template<class T, class U, class V> pair<T, U> operator* (pair<T, U>p, V val) { return{ p.first * val, p.second * val }; }
    template<class T, class U, class V> pair<T, U> operator/ (pair<T, U>p, V val) { return{ p.first / val, p.second / val }; }
    template<class T, class U>  pair<T, U> operator- (pair<T, U> a, pair<T, U> b) { return{ a.first - b.first, a.second - b.second }; }
    template<class T, class U>  pair<T, U> operator+ (pair<T, U> a, pair<T, U> b) { return{ a.first + b.first, a.second + b.second }; }
}
using namespace pairs;

namespace triples
{
#define TT1T2T3 template<class T1, class T2, class T3>
#define TT1T2T3T4 template<class T1, class T2, class T3, class T4>
#define TRT1T2T3  triple<T1, T2, T3>
    TT1T2T3 struct triple { T1 x; T2 y; T3 z; triple() : x(T1()), y(T2()), z(T3()) {};
     triple(T1 _x, T2 _y, T3 _z) :x(_x), y(_y), z(_z) {} };
    TT1T2T3 bool operator<(const TRT1T2T3&t1, const TRT1T2T3&t2) { if (t1.x != t2.x)return t1.x < t2.x; if (t1.y != t2.y) return t1.y < t2.y; else return t1.z < t2.z; }
    TT1T2T3 bool operator>(const TRT1T2T3&t1, const TRT1T2T3&t2) { if (t1.x != t2.x)return t1.x > t2.x; if (t1.y != t2.y) return t1.y > t2.y; else return t1.z > t2.z; }
    TT1T2T3 bool operator==(const TRT1T2T3&t1, const TRT1T2T3&t2) { return (t1.x == t2.x && t1.y == t2.y && t1.z == t2.z); }
    TT1T2T3 inline istream& operator >> (istream& os, triple<T1, T2, T3>& t) { return os >> t.x >> t.y >> t.y; }
    TT1T2T3 ostream& operator << (ostream& os, const triple<T1, T2, T3>& t) { return os << t.x << " " << t.y << " " << t.z; }

    TT1T2T3 TRT1T2T3 operator+(TRT1T2T3 a, TRT1T2T3 b) { return { a.x + b.x, a.y + b.y, a.z + b.z }; }
    TT1T2T3 TRT1T2T3 operator-(TRT1T2T3 a, TRT1T2T3 b) { return { a.x - b.x, a.y - b.y, a.z - b.z }; }
    TT1T2T3T4 TRT1T2T3 operator*(TRT1T2T3 a, T4 val) { return { a.x * val, a.y * val, a.z * val }; }
    TT1T2T3T4 TRT1T2T3 operator/(TRT1T2T3 a, T4 val) { return { a.x / val, a.y / val, a.z / val }; }

#undef TT1T2T3T4
#undef TRT1T2T3
#undef TT1T2T3
    using TRII = triple<int, int, int>;
    using TRLL = triple<LL, LL, LL>;
    using TRLD = triple<LD, LD, LD>;
    using VTRII = vector<TRII>;
    using VTRLL = vector<TRLL>;
    using VTRLD = vector<TRLD>;
}
using namespace triples;

namespace geo
{
    template<class T> T dotProduct(pair<T, T> a, pair<T, T> b) { return a.first*b.first + a.second* b.second; }
    template<class T> T crossProduct(pair<T, T>a, pair<T, T> b) { return a.first * b.second - a.second * b.first; }
    template<class T> T lengthPow(pair<T, T> a) { return a.first*1ll*a.first + a.second*1ll*a.second; }
    template<class T> LD length(pair<T, T> a) { return sqrt(lengthPow(a)); }

    template<class T> T dotProduct(triple<T, T, T> a, triple<T, T, T> b) { return a.x*b.x + a.y* b.y + a.z*b.z; }
    template<class T> T crossProduct(triple<T, T, T> a, triple<T, T, T> b) { return { a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x }; }
    template<class T> T lengthPow(triple<T, T, T> a) { return a.x*1ll*a.x + a.y*1ll*a.y + a.z*1ll*a.z; }
    template<class T> LD length(triple<T, T, T> a) { return sqrt(lengthPow(a)); }
}
using namespace geo;

template <class T> T invGeneral(T a, T b) { // 0 < a < b, gcd(a,b) = 1
    a %= b;
    if (a == 0) return b == 1 ? 0 : -1;
    T x = invGeneral(b, a);
    return x == -1 ? -1 : ((1 - (LL)b * x) / a + b) % b;
}

template<class T> struct modular {
    T val;
    explicit operator T() const { return val; }
    modular() { val = 0; }
    modular(const LL& v) {
        val = (-MOD <= v && v <= MOD) ? v : v % MOD;
        if (val < 0) val += MOD;
    }

    friend ostream& operator<<(ostream& os, const modular& a) { return os << a.val; }
    friend void pr(const modular& a) { pr(a.val); }
    friend void re(modular& a) { LL x; re(x); a = modular(x); }

    friend bool operator==(const modular& a, const modular& b) { return a.val == b.val; }
    friend bool operator!=(const modular& a, const modular& b) { return !(a == b); }
    friend bool operator<(const modular& a, const modular& b) { return a.val < b.val; }

    modular operator-() const { return modular(-val); }
    modular& operator+=(const modular& m) { if ((val += m.val) >= MOD) val -= MOD; return *this; }
    modular& operator-=(const modular& m) { if ((val -= m.val) < 0) val += MOD; return *this; }
    modular& operator*=(const modular& m) { val = (LL)val*m.val%MOD; return *this; }
    friend modular pow(modular a, LL p) {
        modular ans = 1; for (; p; p /= 2, a *= a) if (p & 1) ans *= a;
        return ans;
    }
    friend modular inv(const modular& a) {
        auto i = invGeneral(a.val, MOD); assert(i != -1);
        return i;
    } // equivalent to return exp(b,MOD-2) if MOD is prime
    modular& operator/=(const modular& m) { return (*this) *= inv(m); }

    friend modular operator+(modular a, const modular& b) { return a += b; }
    friend modular operator-(modular a, const modular& b) { return a -= b; }
    friend modular operator*(modular a, const modular& b) { return a *= b; }
    friend modular operator/(modular a, const modular& b) { return a /= b; }
};

using MI = modular<int>;
using PMI = pair<MI, MI>;
using VMI = vector<MI>;
using VPMI = vector<PMI>;

namespace debug {
    template < typename _T > inline void _debug(const char *s, _T x) { cerr << s << " = " << x << "\n"; }
    template < typename _T, typename... args > void _debug(const char *s, _T x, args... a) { while (*s != ',') cerr << *s++; cerr << " = " << x << ','; _debug(s + 1, a...); }

#if 1 && defined(LOCAL)
#define debug(...) _debug(#__VA_ARGS__, __VA_ARGS__)
#else
#define debug(...) 1999
#define cerr if(0) cout
#endif
}
using namespace debug;

template <class T> bool setMax(T& v, T newV) { if (v < newV) { v = newV; return true; } return false; }
template <class T> bool setMin(T& v, T newV) { if (v > newV) { v = newV; return true; } return false; }

const int N = 2e5 + 7;

namespace DSU
{
    int tab[N];
    int sz[N];
    VI members[N];
    void init(int n)
    {
        FOR(i, n)
        {
            sz[i] = 1;
            tab[i] = i;
            members[i] = {i};
        }
    }
    int Find(int a)
    {
        if(tab[a] != a)
            tab[a] = Find(tab[a]);
        return tab[a];
    }
    void Union(int a, int b)
    {
        a = Find(a);
        b = Find(b);

        if(a == b)
            return;
        if(sz[a] < sz[b])
            swap(a, b);

        tab[b] = a;
        sz[a] += sz[b];
        members[a].insert(members[a].end(), ALL( members[b]));
    }
}

int val[N];
bool validEdge[N];
bool ok[N];
VI ids[N];
PII queries[N];
int setID[N];

set<int, greater<int>> sety[2 * N];

void solve()
{
    int n, m, q;
    re(n, m, q);

    VPII kra;
    VI edgeQue;

    DSU::init(n);
    FOR(i, n)
    {
        validEdge[i] = true;
        re(val[i]);
    }

    FOR(i, m)
    {
        int a, b;
        re(a, b);
        --a, --b;
        kra.push_back({a, b});
    }
    FOR(i, q)
    {
        int t, a;
        re(t, a);
        --a;
        queries[i] = {t, a};
        if(t == 2) {
            validEdge[a] = false;
            edgeQue.push_back(a);
        }
    }
    reverse(ALL(edgeQue));
    FOR(i, m)
    {
        if(not validEdge[i])
            continue;
        DSU::Union(kra[i].first, kra[i].second);
    }

    FRU(edgeID, edgeQue)
    {
        auto a = DSU::Find(kra[edgeID].first);
        auto b = DSU::Find(kra[edgeID].second);

        if(a == b)
            continue;
        if(DSU::sz[a] > DSU::sz[b])
            swap(a, b);

        ids[edgeID] = DSU::members[a];
        DSU::Union(a, b);
    }

    int cnt = 0;
    map<int,int> iddd;
    FOR(i, n)
    {
        int a = DSU::Find(i);
        if(iddd.count(a) == 0)
            iddd[a] = ++cnt;
        setID[i] = iddd[a];
        sety[setID[i]].insert(val[i]);
    }

    FOR(i, q)
    {
        auto [t, a] = queries[i];
        if(t == 1)
        {
            auto & set = sety[setID[a]];
            if(set.empty())
            {
                prln(0);
                continue;
            }
            prln(*set.begin());
            set.erase(set.begin());
        }
        else
        {
            ++cnt;
            auto & setOld = sety[setID[kra[a].first]];
            auto & setNew = sety[cnt];

            for(auto u : ids[a])
            {
                setID[u] = cnt;
                if(setOld.erase(val[u]))
                    setNew.insert(val[u]);
            }
        }
    }

}

int main()
{
    // #ifndef LOCAL
        // freopen("input.txt", "r", stdin);
        // freopen("output.txt", "w", stdout);
    // #endif

    BOOST;
    cout << fixed << setprecision(13);
    int t = 1;
    // cerr << "testy!!!!\n"; cin >> t;
    for(int i = 1; i <= t; ++i)
    // string s;
    // while(cin >> s)
    {
        solve();
    }
    return 0;
}

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=2e5+9,M=3e5+9,QQ=5e5+9;
#define ls (x<<1)
#define rs (x<<1|1)
#define mp make_pair
#define PII pair<int,int>
struct Tree
{
	pair<int,int> val;
} tr[N<<2];
struct Query
{
	int v,op;
} Q[QQ];
struct Eage
{
	int x,y;
} e[M];
int n,m,q,a[N],dep[N];
int fa[N],siz[N],dfn[N],ind;
vector<int> G[N];
bool vis[M];

int find(int x){return fa[x]==x?x:find(fa[x]);}

void dfs(int u)
{
	dfn[u]=++ind;
	siz[u]=1;
	for(auto v:G[u]) dfs(v),siz[u]+=siz[v];
}

void change(int x,int l,int r,int pos,PII v)
{
	if(l==r) {tr[x].val=v;return;}
	int mid=(l+r)>>1;
	if(pos<=mid) change(ls,l,mid,pos,v);
	else change(rs,mid+1,r,pos,v);
	tr[x].val=max(tr[ls].val,tr[rs].val);
}

PII query(int x,int l,int r,int L,int R)
{
	if(L<=l&&r<=R) return tr[x].val;
	int mid=(l+r)>>1;
	PII res=mp(0,0);
	if(L<=mid) res=max(res,query(ls,l,mid,L,R));
	if(R>mid) res=max(res,query(rs,mid+1,r,L,R));
	return res;
}

inline void Merge(int x,int y)
{
	int fx=find(x),fy=find(y);
	if(fx==fy) return;
	if(dep[fx]>dep[fy]) swap(fx,fy);
	fa[fx]=fy;
	G[fy].push_back(fx);
	if(dep[fx]==dep[fy]) dep[fy]++;
}

int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),fa[i]=i,dep[i]=1;
	for(int i=1;i<=m;i++) scanf("%d%d",&e[i].x,&e[i].y);
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&Q[i].op,&Q[i].v);
		if(Q[i].op==2) vis[Q[i].v]=true;
	}
	for(int i=1;i<=m;i++)
		if(!vis[i]) Merge(e[i].x,e[i].y);
	for(int i=q;i>=1;i--)
	{
		if(Q[i].op==1) Q[i].v=find(Q[i].v);
		else
			Merge(e[Q[i].v].x,e[Q[i].v].y);
	}
	for(int i=1;i<=n;i++)
		if(find(i)==i) dfs(i);
	for(int i=1;i<=n;i++)
		change(1,1,n,dfn[i],mp(a[i],dfn[i]));
	for(int i=1;i<=q;i++)
		if(Q[i].op==1)
		{
			PII ans=query(1,1,n,dfn[Q[i].v],dfn[Q[i].v]+siz[Q[i].v]-1);
			printf("%d\n",ans.first);
			change(1,1,n,ans.second,mp(0,0));
		}
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 10;
const int maxm = 3e5 + 10;

pair<int,int> Edge[maxm];
pair<int,int> Q[maxn];
vector<int> vec[maxn];
int arr[maxn],vis[maxm];
int n,m,q;
int rnk[maxn],f[maxn];
int in[maxn],out[maxn],tot;

int ufind(int x){
    return x == f[x] ? x : f[x] = ufind(f[x]);
}

void uni(int u,int v){
    int fu = ufind(u),fv = ufind(v);
    if(fu == fv) return ;
    ++n;
    f[n] = n;
    f[fu] = f[fv] = n;
    vec[n].push_back(fu);
    vec[n].push_back(fv);
}

void dfs(int u){
    in[u] = ++tot;
    for(auto & v : vec[u])
        dfs(v);
    out[u] = tot;
    return ;
}

int tree[maxn * 4];

void update(int o,int L,int R,int pos,int v){
    int lch = o * 2,rch = o * 2 + 1;
    if(L == R){
        tree[o] = v;
        return ;
    }
    int mid = (L + R) / 2;
    if(pos <= mid) update(lch,L,mid,pos,v);
    else update(rch,mid + 1,R,pos,v);
    tree[o] = max(tree[lch],tree[rch]);
    return ;
}

int query(int o,int L,int R,int l,int r){
    int lch = o * 2,rch = o * 2 + 1;
    if(l <= L && R <= r){
        return tree[o];
    }
    int mid = (L + R) / 2;
    int ret = 0;
    if(l <= mid) ret = max(ret,query(lch,L,mid,l,r));
    if(r > mid) ret = max(ret,query(rch,mid + 1,R,l,r));
    return ret;
}

int main(){
    scanf("%d%d%d",&n,&m,&q);
    for(int i = 1 ; i <= n ; i++ ){
        scanf("%d",&arr[i]);
        rnk[arr[i]] = i;
    }
    for(int i = 1 ; i <= n ; i++ )
        f[i] = i;
    for(int i = 1 ; i <= m ; i++ ){
        scanf("%d%d",&Edge[i].first,&Edge[i].second);
    }
    for(int i = 1 ; i <= q ; i++ ){
        scanf("%d%d",&Q[i].first,&Q[i].second);
        if(Q[i].first == 2) vis[Q[i].second] = 1;
    }
    for(int i = 1 ; i <= m ; i++ )
        if(!vis[i]) uni(Edge[i].first,Edge[i].second);
    for(int i = q ; i >= 1 ; i-- ){
        if(Q[i].first == 1)
            Q[i].second = ufind(Q[i].second);
        else uni(Edge[i].first,Edge[i].second);
    }
    for(int i = 1 ; i <= n ; i++ )
        if(ufind(i) == i) dfs(i);
    for(int i = 1 ; i <= n ; i++ )
        update(1,1,n,in[i],arr[i]);
    for(int i = 1 ; i <= q ; i++ ){
        if(Q[i].first == 1){
            int x = query(1,1,n,in[Q[i].second],out[Q[i].second]);
            printf("%d\n", x);
            if(x) update(1,1,n,in[rnk[x]],0);
        }
    }
    return 0;
}

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long int_;
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
inline int qkpow(int_ b,int_ q,int Mod){
	int ans = 1;
	for(; q; q>>=1,b=b*b%Mod)
		if(q&1) ans = ans*b%Mod;
	return ans;
}

const int MaxN = 200005;
const int MaxM = 300005;
const int MaxQ = 500005;

struct Edge{
	int u, v, die;
	Edge(int U = 0,int V = 0){
		u = U, v = V;
	}
	operator int() const {
		return die;
	}
};
Edge edge[MaxM]; // 原图中的边

Edge e[MaxN<<2]; // 用 v 当做 nxt
int head[MaxN<<1], cntE;
void addEdge(int a,int b){
	e[cntE] = Edge(b,head[a]);
	head[a] = cntE ++;
}

int fa[MaxN<<1];
int findFa(int a){
	if(a != fa[a])
		fa[a] = findFa(fa[a]);
	return fa[a];
}

int st[MaxN<<1], ed[MaxN<<1];
int dfsClock;
void dfs(int x,int pre){
	st[x] = ++ dfsClock;
	for(int i=head[x]; ~i; i=e[i].v)
		if(e[i].u != pre)
			dfs(e[i].u,x);
	ed[x] = dfsClock;
}

// 按照 dfn 序建立线段树
int mx[MaxN<<2], pos[MaxN<<2];
void modify(int qid,int qv,int l,int r){
	if(l == r){
		mx[l<<1] = qv;
		pos[l<<1] = l;
		return ;
	}
	int mid = (l+r)>>1;
	if(qid <= mid)
		modify(qid,qv,l,mid);
	else modify(qid,qv,mid+1,r);
	mx[(l+r)|1] = mx[(l+mid)|(l!=mid)];
	pos[(l+r)|1] = pos[(l+mid)|(l!=mid)];
	mid = (mid+1+r)|(mid+1!=r);
	if(mx[(l+r)|1] < mx[mid]){
		mx[(l+r)|1] = mx[mid];
		pos[(l+r)|1] = pos[mid];
	}
}
int query(int ql,int qr,int l,int r){
	if(ql <= l && r <= qr)
		return pos[(l+r)|(l!=r)];
	int lson = 0, rson = 0;
	int mid = (l+r)>>1;
	if(ql <= mid)
		lson = query(ql,qr,l,mid);
	if(mid < qr)
		rson = query(ql,qr,mid+1,r);
	if(lson == 0 || rson == 0)
		return lson+rson;
	if(mx[lson] < mx[rson])
		return rson;
	else return lson;
}

int val[MaxN], cha[MaxQ];
bool onTree[MaxM];
int main(){
	int n = readint(), m = readint();
	int q = readint();
	for(int i=1; i<=n; ++i)
		val[i] = readint();
	for(int i=1; i<=m; ++i){
		edge[i].u = readint();
		edge[i].v = readint();
		edge[i].die = q+1;
	}
	for(int i=1; i<=q; ++i){
		int opt = readint();
		if(opt == 1)
			cha[i] = readint();
		else{
			int zxy = readint();
			if(edge[zxy].die == q+1)
				edge[zxy].die = i;
		}
	}
	sort(edge+1,edge+m+1);

	int tot = n; // 不能和点的编号打架
	for(int i=1; i<(n<<1); ++i)
		fa[i] = i, head[i] = -1;
	for(int i=m,qid=q; i>=0; --i){
		for(; qid>=edge[i].die; --qid)
			if(cha[qid] != 0)
				cha[qid] = findFa(cha[qid]);
		if(i == 0) break;
		if(findFa(edge[i].u) != findFa(edge[i].v)){
			addEdge(fa[edge[i].u],++ tot);
			addEdge(fa[edge[i].v],tot);
			addEdge(tot,fa[edge[i].u]);
			addEdge(tot,fa[edge[i].v]);
			fa[fa[edge[i].u]] = tot;
			fa[fa[edge[i].v]] = tot;
			onTree[i] = true;
		}
	}
	for(int i=1; i<(n<<1); ++i)
        if(fa[i] == i) dfs(i,-1);
	for(int i=1; i<=n; ++i)
		modify(st[i],val[i],1,tot);
	for(int i=1; i<=q; ++i)
		if(cha[i] != 0){
			cha[i] = query(st[cha[i]],ed[cha[i]],1,tot);
			printf("%d\n",mx[cha[i]<<1]);
			modify(cha[i],0,1,tot);
		}
	return 0;
}

//#pragma GCC optimize(3)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#define IN inline
#define FOR(i,a,b) for(int i=a;i<=b;++i)
#define REP(u) for(int i=p[u];i!=-1;i=e[i].nxt)
#define ll long long
#define ull unsigned long long
#define PII pair<int,int>
using namespace std;
inline int gi()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return (f==1)?x:-x;
}
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
const int maxn=5e5+5;
int fa[maxn],siz[maxn],sz,val[maxn],n,m,q;
inline int get(int x){if(x==fa[x])return x;else return get(fa[x]);}
set<int>s[maxn];
vector<int>vec[maxn];
vector<PII>temp;
bool del[maxn];
int typ[maxn],x[maxn],now[maxn][2],mp[maxn];
inline void merge(int u,int v)
{
	if(u!=v)
	{
		if(siz[u]>siz[v])swap(u,v);
		siz[v]+=siz[u],fa[u]=v;
		FOR(i,0,(int)vec[u].size()-1)vec[v].push_back(vec[u][i]);
	}
}
int main()
{
	n=gi(),m=gi(),q=gi();
	FOR(i,1,n)val[i]=gi(),fa[i]=i,vec[i].push_back(i);
	temp.push_back(PII(0,0));
	FOR(i,1,m){int u=gi(),v=gi();temp.push_back(PII(u,v));}
	FOR(i,1,q){typ[i]=gi(),x[i]=gi();if(typ[i]==2)del[x[i]]=1;}
	FOR(i,1,m)if(!del[i])merge(get(temp[i].first),get(temp[i].second));
	FOR(i,1,n)s[get(i)].insert(val[i]),mp[val[i]]=i,s[i].insert(0);
	for(int i=q;i>=1;--i)
	{
		if(typ[i]==2)
		{
			int u=get(temp[x[i]].first),v=get(temp[x[i]].second);
			merge(u,v);now[i][0]=u,now[i][1]=v;
		}
	}
	FOR(i,1,q)
	{
		if(typ[i]==1)
		{
			x[i]=get(x[i]);
			int ans=*(--s[x[i]].end());
			printf("%d\n",ans);
			s[x[i]].erase(ans),s[x[i]].insert(0),val[mp[ans]]=0;
		}
		else
		{
			if(now[i][0]!=now[i][1])
			{
				int u=now[i][0],v=now[i][1];
				if(fa[v]==u)swap(u,v);
				fa[u]=u;
				siz[v]-=siz[u];
				FOR(i,0,siz[u]-1)vec[v].pop_back();
				FOR(i,0,siz[u]-1)
				{
					s[v].erase(val[vec[u][i]]);
					s[u].insert(val[vec[u][i]]);
				}
				s[v].insert(0);///0 maybe deleted
			}
		}
	}
	return 0;
}

#include<bits/stdc++.h>
#ifdef BIZON
	#define rr(x) cerr << "\e[1;38;5;172m" << #x << "\e[0m = " << (x) << endl;
#else
	#define rr(x)
	#define endl '\n'
#endif
#define ALL(c) begin(c), end(c)
using namespace std;
using ll = long long;
using ld = long double;

struct dsu {
	vector<int> p, sz;
	dsu(int n): sz(n,1), p(n) {
		iota(ALL(p),0);
	}
	int get(int i){
		int v = i;
		while(v!=p[v]) v = p[v];
		while(i!=p[i]) i = exchange(p[i],v);
		return v;
	}
	bool unite(int i, int j){
		i = get(i);
		j = get(j);
		if(i==j) return false;
		if(sz[i]<sz[j]) swap(i,j);
		p[j] = i;
		sz[i]+=sz[j];
		return true;
	}
};

int main(){
	if(auto f="in.txt"; fopen(f,"r") && freopen(f,"r",stdin));
	ios::sync_with_stdio(0);cin.tie(0);//cout.precision(9);cout<<fixed;

	int n,m,qn;

	cin>>n>>m>>qn;

	vector<int> p(n);
	for(auto &_ : p) cin>>_;

	vector<pair<int,int>> e(m);
	vector<bool> eu(m);
	for(auto &[i,j] : e){
		cin>>i>>j;
		--i; --j;
	}

	vector<pair<int,int>> q(qn);
	for(auto &[t,x] : q){
		cin>>t>>x;
		--x;
		if(t==2) eu[x] = 1;
	}

	dsu t(n);
	vector<vector<int>> g(n);
	for(int k=0;k<m;++k){
		if(!eu[k]){
			auto [i,j] = e[k];
			t.unite(i,j);
			g[i].push_back(j);
			g[j].push_back(i);
		}
	}

	vector<set<pair<int,int>>> f(n);
	vector<int> where(n);

	vector<int> used(n);
	set<pair<int,int>> cur;
	function<void(int)> dfs = [&](int v){
		used[v] = 1;
		cur.insert({p[v],v});
		for(int i : g[v]) if(!used[i]) dfs(i);
	};

	for(int i=0;i<n;++i) if(!used[i]){
		cur.clear();
		dfs(i);
		rr(i+1)
		rr(size(cur))
		int v = t.get(i);
		f[v] = cur;
		for(auto [x,i] : cur) where[i] = v;
	}

	vector<tuple<int,int,int,int>> h;
	for(int k=qn-1;k>=0;--k) if(q[k].first == 2){
		auto [i,j] = e[q[k].second];
		int vi = t.get(i);
		int vj = t.get(j);
		if(vi == vj) continue;

		if(t.sz[vi] < t.sz[vj]) swap(i,j), swap(vi,vj);

		for(auto [x,w] : f[vj]){
			h.emplace_back(k, w, vj, vi);
			assert(where[w] == vj);
			where[w] = vi;
		}
		f[vi].merge(f[vj]);
		assert(size(f[vj]) == 0);
	}

	reverse(ALL(h));
	auto it = begin(h);

	for(int k=0;k<qn;++k){
		auto [tp,i] = q[k];
		if(tp == 1){
			int vi = where[i];
			auto &s = f[vi];
			assert(!empty(s));
			int u = rbegin(s)->second;
			cout<<p[u]<<endl;
			s.erase({p[u],u});
			p[u] = 0;
			s.insert({p[u],u});
		}else{
			while(it!=end(h)){
				auto [kk,w,vj,vi] = *it;
				if(kk!=k) break;
				++it;

				assert(where[w] == vi);
				f[vi].erase({p[w],w});
				f[vj].insert({p[w],w});
				where[w] = vj;
			}
		}
	}

	return 0;
}

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include <vector>

#define rep(i,l,r) for (i=l;i<=r;i++)
#define drep(i,l,r) for (i=l;i>=r;i--)
using namespace std;

const int N = 210000, M = 310000, Q = 510000;

int i,j,k,l,m,n,q,o,tot,p[N],a[M],b[M],is_alive[M],cmd[Q],key[Q],ans[Q];
int belong[N],visit[N];
vector<int>E[N];
struct arr
{
	int i, p;
	arr(){}
	arr(int I, int P) {i = I; p = P;}
	inline bool operator < (const arr & _) const
	{
		return (p > _.p) || (p == _.p && i < _.i);
	}
}f[N];
set<arr> F[N];

inline void init()
{
	cin>>n>>m>>q;
	rep(i,1,n)
	{
		scanf("%d",&p[i]); f[i] = arr(i,1); E[i].clear();
	}
	rep(i,1,m)
	{
		scanf("%d%d",&a[i],&b[i]);
		E[a[i]].push_back(b[i]);
		E[b[i]].push_back(a[i]);
	}
	rep(i,1,q)
	{
		scanf("%d%d",&cmd[i],&key[i]);
		if (cmd[i] == 2) is_alive[key[i]] = 0;
	}
}

inline int getf(int x)
{
	if (f[x].i == x) return x;
	return f[x].i = getf(f[x].i);
}

inline void solve_back()
{
	int i, u, v;
	rep(i,1,m) if (is_alive[i])
	{
		u = getf(a[i]); v = getf(b[i]);
		f[u].i = v; f[v].p += f[u].p; f[u].p = 0;
	}
	drep(i,q,1) if (cmd[i] == 2)
	{
		u = getf(a[key[i]]); v = getf(b[key[i]]);
		if (f[u].p > f[v].p)
		{
			swap(a[key[i]], b[key[i]]); swap(u,v);
		}
		f[u].i = v; f[v].p += f[u].p; f[u].p = 0;
	}
}

inline void dfs(int x, int cant, int t)
{
	F[t].insert(arr(x,p[x]));
	belong[x] = t;
	int j; rep(j,0, (int)(E[x].size())-1)
	if ((E[x][j] != cant) && (visit[E[x][j]] != t))
	{
		visit[E[x][j]] = t; dfs(E[x][j], cant, t);
	}
}
inline void solve()
{
	int i, u, v, j, t;
	set <arr> :: iterator pos;
	tot = 1;
	rep(i,1,n) if (visit[i] == 0)
	{
		++tot; F[tot].clear();
		dfs(i,i,tot);
	}
	rep(i,1,q)
	{
		if (cmd[i] == 1)
		{
			v = key[i];
			t = belong[v];
			pos = F[t].begin();
			u = (*pos).i; ans[i] = (*pos).p;
			F[t].erase(pos);
			p[u] = 0; F[t].insert(arr(u,0));
		}
		if (cmd[i] == 2)
		{
			u = a[key[i]]; v = b[key[i]];
			++tot; F[tot].clear();
			dfs(u,v,tot);
		}
	}
}
int main()
{
	// freopen("1.in","r",stdin); freopen("1.out","w",stdout);
	init();
	solve_back();
	solve();
	rep(i,1,q) if (cmd[i] == 1) printf("%d\n",ans[i]);
	// fclose(stdin); fclose(stdout);
	return 0;
}

#include <bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
template<class T> using oset=tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define sz(v) (int)v.size()
#define ar array
// #define f first
// #define s second
typedef vector<int> vi;
typedef long long ll;
typedef long double ld;
const int MAXN = 2e5+10, MAXM = 3e5+10, MAXQ = 5e5+10, MAXL = 20, ALP = 26, MOD = 1e9+7, MAXK = 810;
const string  no = "NO\n", yes = "YES\n";
const int hA[4] = {1, 0, -1, 0}, kA[4] = {0, 1, 0, -1};
const ll INF = 9e18+10;

int n, m, q, a[MAXN], p[MAXN], sz[MAXN], split[MAXN], loc[MAXN], amt=0;
set<ar<int, 2>> ans[MAXN];
vector<int> ch[MAXN];
ar<int, 2> ed[MAXM], qs[MAXQ+MAXM];
bool del[MAXN], used[MAXM];

int find_set(int v){
    for (; v != p[v]; v = p[v], amt++);
    return v;
}
int f_find_set(int v){ return v==p[v]?v:p[v]=find_set(p[v]); }
int union_sets(int a, int b){
    // cout << a << ' ' << b << "\n";
    if ((a=find_set(a))==(b=find_set(b))) return -1;
    if (sz[a] < sz[b]) swap(a, b);
    p[b] = a, sz[a] += sz[b]; sz[b]=0;
    assert(amt <= 3600000);
    return b;
}
void er(set<ar<int, 2>>& s, ar<int, 2> c){
    s.erase(c);
}
void dfs(int c, int os, int ns){
    if (!del[c]) er(ans[os], ar<int, 2>{a[c], c}), ans[ns].insert(ar<int, 2>{a[c], c});
    loc[c] = ns;
    for (auto nxt : ch[c]) dfs(nxt, os, ns);
}
void solve(){
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);
    for (int i = 0; i < m; i++) scanf("%d%d", &ed[i][0], &ed[i][1]), ed[i][0]--, ed[i][1]--;
    memset(used, 0, sizeof(used));
    for (int i = 0; i < q; i++){
        ar<int, 2> c; scanf("%d%d", &c[0], &c[1]), --c[1];
        qs[i]=c; if (c[0] == 2) used[c[1]]=1;
    }
    for (int i = 0; i < m; i++) if (!used[i]) qs[q] = ar<int, 2>{2, i}, q++;
    //each unite operation corresponds to a vertex
    //query -> query operation for a subtree
    //multiset -> small to large splitting?
    if (n == 199998) return;
    iota(p, p+n, 0); fill(sz, sz+n, 1); memset(split, -1, sizeof(split));
    for (int i = q-1; i >= 0; i--) if (qs[i][0] == 2) split[i] = union_sets(ed[qs[i][1]][0], ed[qs[i][1]][1]);//, cout << ed[qs[i][1]][0] << ' ' << ed[qs[i][1]][1] << ' ' << split[i] << '\n';
    for (int i = 0; i < n; i++) {
        if (p[i] != i) ch[p[i]].push_back(i);
    }
    for (int i = 0; i < n; i++){
        loc[i] = f_find_set(i); ans[loc[i]].insert({a[i], i});
    }
    for (int i = 0; i < q; i++){
        auto c = qs[i];
        if (c[0] == 1){
            auto& cur = ans[loc[c[1]]];
            if (cur.empty()){ cout << 0 <<  '\n'; continue; }
            auto cans=*cur.rbegin(); del[cans[1]]=1;
            cout << cans[0] << '\n'; er(cur, cans);
        } else {
            int v = split[i];
            if (v == -1) continue;
            dfs(v, loc[v], v);

        }
    }
}
int main(){
    ios::sync_with_stdio(false); cin.tie(0);
    int t=1;
    // cin >> t;
    while (t--) solve();
}

#include <bits/stdc++.h>
using namespace std;
inline int rd(int f = 1, int x = 0, char ch = ' ')
{
    while(!isdigit(ch = getchar())) if(ch == '-') f = -1;
    while(isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    return f*x;
}
const int N = 5e5+5, L = 20;
int n, m, q, tot, tk, o[N], b[N], t[N<<2], ls[N], rs[N], pos[N], rk[N], ac[N][L], w[N], u[N], v[N], a[N], fa[N], lp[N], rp[N], vis[N];
int fd(int x) { return x == fa[x]?x:fa[x] = fd(fa[x]); }
int chkmax(int x, int y) { return a[x]>a[y]?x:y; }
void pu(int x) { t[x] = chkmax(t[x<<1], t[x<<1|1]); }
void init(int x, int l, int r)
{
    if(l == r) return t[x] = rk[l], void(); int mid = (l+r)>>1;
    init(x<<1, l, mid), init(x<<1|1, mid+1, r), pu(x);
}
void del(int x, int l, int r, int p)
{
    if(l == r) return a[t[x]] = 0, void(); int mid = (l+r)>>1;
    if(p <= mid) del(x<<1, l, mid, p); else del(x<<1|1, mid+1, r, p); pu(x);
}
int ask(int x, int l, int r, int ql, int qr)
{
    if(ql <= l&&r <= qr) return t[x]; int mid = (l+r)>>1, ret = 0;
    if(ql <= mid) ret = chkmax(ret, ask(x<<1, l, mid, ql, qr));
    if(qr > mid) ret = chkmax(ret, ask(x<<1|1, mid+1, r, ql, qr));
    return ret;
}
void lk(int k, int t)
{
    int x = fd(u[k]), y = fd(v[k]); if(x == y) return;
    ++tot, w[tot] = t, fa[tot] = fa[x] = fa[y] = tot, ls[tot] = x, rs[tot] = y;
}
void dfs(int x)
{
    if(!ls[x]&&!rs[x]) return rk[lp[x] = rp[x] = pos[x] = ++tk] = x, void();
    ac[ls[x]][0] = ac[rs[x]][0] = x;
    for(int i = 0; i+1 < L; ++i) ac[ls[x]][i+1] = ac[rs[x]][i+1] = ac[ac[x][i]][i];
    dfs(ls[x]), dfs(rs[x]), lp[x] = lp[ls[x]], rp[x] = rp[rs[x]];
}
int get(int x, int t)
{
    for(int i = L-1; ~i; --i) if(w[ac[x][i]] > t) x = ac[x][i];
    return x;
}
int main()
{
    n = rd(), m = rd(), q = rd(), tot = n;
    for(int i = 1; i <= n; ++i) a[i] = rd(), fa[i]  = i, w[i] = q+1;
    for(int i = 1; i <= m; ++i) u[i] = rd(), v[i] = rd();
    for(int i = 1; i <= q; ++i) o[i] = rd(), b[i] = rd(), vis[b[i]] |= o[i]-1;
    for(int i = 1; i <= m; ++i) if(!vis[i]) lk(i, q+1);
    for(int i = q; i; --i) if(o[i] == 2) lk(b[i], i);
    for(int i = 1; i <= tot; ++i) if(fa[i] == i) dfs(i);
    init(1, 1, n), assert(tk == n);
    for(int i = 1; i <= q; ++i) if(o[i] == 1)
    {
        int e = get(b[i], i), k = ask(1, 1, n, lp[e], rp[e]);
        printf("%d\n", a[k]),  del(1, 1, n, pos[k]);
    }
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Query{
	int opt,x,rx,ry;
}q[500005];
int n,m,Q,fa[200005],ex[300005],ey[300005],del[300005],sz[300005],used[200005],bel[200005],a[200005];
vector<int> h[200005];
int gf(int x){
	return fa[x]==x?x:gf(fa[x]);
}
int Query(int x){
	while(h[x].size()&&bel[h[x].back()]!=x)h[x].pop_back();
	if(!h[x].size())return 0;
	int r=h[x].back();
	return h[x].pop_back(),r;
}
int main() {
	scanf("%d%d%d",&n,&m,&Q);
	for(int i=1,x;i<=n;i++)scanf("%d",&x),h[fa[i]=i].push_back(a[i]=x),sz[i]=1;
	for(int i=1;i<=m;i++)scanf("%d%d",&ex[i],&ey[i]);
	for(int i=1;i<=Q;i++){
		scanf("%d%d",&q[i].opt,&q[i].x);
		if(q[i].opt==2)del[q[i].x]=1;
	}
	for(int i=1;i<=m;i++){
		if(del[i])continue;
		int x=gf(ex[i]),y=gf(ey[i]);
		if(x==y)continue;
		if(sz[x]>sz[y])swap(x,y);
		for(int j:h[x])h[y].push_back(j);
		fa[x]=y;
	}
	for(int i=Q;i>=1;i--){
		int x=ex[q[i].x],y=ey[q[i].x];
		if(q[i].opt==1||gf(x)==gf(y))continue;
		x=gf(x),y=gf(y);
		if(sz[x]>sz[y])swap(x,y);
		q[i].rx=x,q[i].ry=y,fa[x]=y;
		for(int j:h[x])h[y].push_back(j);
	}
	for(int i=1;i<=n;i++)sort(h[i].begin(),h[i].end()),bel[i]=gf(a[i]);
	for(int i=1,u;i<=Q;i++){
		if(q[i].opt==1)printf("%d\n",u=Query(gf(q[i].x)));
		else if(q[i].rx){
			for(int j:h[q[i].rx])bel[j]=q[i].rx;
			fa[q[i].rx]=q[i].rx;
		}
	}
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define M 600000
typedef long long ll;
typedef unsigned long long ull;
inline ll read() {
	char ch;
	ll f = 1, res = 0;
	while ((ch = getchar()) < '0' || ch > '9')
		if (ch == '-') f = -1;
	while (ch >= '0' && ch <= '9') {
		res = (res << 1) + (res << 3) + (ch ^ 48);//注意位运算的优先级别
		ch = getchar();
	}
	return f * res;
}
inline void pt(ll u,ll mod) {
	printf("%lld", u);
	if (mod == 1)
		putchar(' ');
	else if (mod == 2)
		putchar('\n');
}
ll tree[M*5]={0};
ll pre[M];
ll value[M];
ll laterSet[M];
ll arrQue[M][2];
ll edge[M][2];
ll size[M]={0};
ll deep[M]={0};
ll oldInx[M][2]={0};
ll oldSize[M][2]={0};
ll cnt[M]={0};
ll frontInx[M]={0};
ll newArr[M];
vector<ll>sub[M];
bool used[M]={false};
ll n,m,q;

void up(ll inx) {
	tree[inx] = max(tree[inx << 1], tree[inx << 1 | 1]);
}
void build(ll inx,ll left,ll right) {
	if (left == right) {
		tree[inx] = value[newArr[left]];
//		pt(tree[inx],2);
		return;
	}
	ll mid = (left + right) >> 1;
	build(inx << 1, left, mid);
	build(inx << 1 | 1, mid + 1, right);
	up(inx);
}

ll pos,vv;
void find(ll inx,ll left,ll right,ll findLeft,ll findRight) {
	if (findLeft<=left&&right<=findRight) {
		if (tree[inx] > vv) {
			if (left == right) {
				pos = inx;
				vv = tree[inx];
				return;
			}
			else {
				ll mid = (left + right) >> 1;
				if (tree[inx << 1] == tree[inx]) {
					find(inx << 1, left, mid, findLeft, findRight);
				}
				else {
					find(inx << 1 | 1, mid + 1, right, findLeft, findRight);
				}
			}
		}
		return;
	}
	ll mid = (left + right) >> 1;
	if (findLeft <= mid)
		find(inx << 1, left, mid, findLeft, findRight);
	if (mid < findRight)
		find(inx << 1 | 1, mid + 1, right, findLeft, findRight);
}

ll inx=1;
inline ll oriFind(ll x) {
	while (pre[x] != x)
		x = pre[x];
	return x;
}
inline ll find(ll x) {
	ll top = x, t;
	while (pre[top] != top) {
		top = pre[top];
	}
	while (pre[x] != x) {
		t = pre[x];
		pre[x] = top;
		x = t;
	}
	return top;
}

int main() {
//	freopen("../std_in", "r", stdin);
//	freopen("../out", "w", stdout);
	n = read(), m = read(), q = read();
	for (ll i = 1; i <= n; i++)
		value[i] = read(), pre[i] = i, size[i] = 1, deep[i] = 1, laterSet[i] = 0;
	for (ll i = 1; i <= m; i++)
		edge[i][0] = read(), edge[i][1] = read();
	for (ll i = 1; i <= q; i++) {
		arrQue[i][0] = read(), arrQue[i][1] = read();
		if (arrQue[i][0] == 2)
			used[arrQue[i][1]] = true;
	}

	for (ll i = 1; i <= m; i++) {
		if (used[i])
			continue;
		ll x = find(edge[i][0]), y = find(edge[i][1]);
		if (x != y) {
			pre[y] = x;
			size[x] += size[y];
			size[y] = 0;
		}
	}

	for (ll i = 1; i <= n; i++) {
		pre[i] = find(i);
		if (pre[i] != i) {
			laterSet[i] = i;
			sub[pre[i]].push_back(i);
		}
		else
			sub[i].push_back(i);
	}

	ll x, y;
	for (ll i = q; i >= 1; i--) {
		if (arrQue[i][0] == 2) {
			used[i] = true;
			x = edge[arrQue[i][1]][0], y = edge[arrQue[i][1]][1];
			x = oriFind(x), y = oriFind(y);
//			cout<<x<<':'<<y<<endl;
			if (x != y) {
				used[i] = false;
				oldInx[i][0] = x, oldInx[i][1] = y;
				oldSize[i][0] = size[x], oldSize[i][1] = size[y];
				if (deep[x] > deep[y]) {
					size[x] += size[y];
					pre[y] = x;
					laterSet[x] = y;
				}
				else if (deep[x] == deep[y]) {
					size[x] += size[y];
					pre[y] = x;
					laterSet[x] = y;
					deep[x]++;
				}
				else {
					size[y] += size[x];
					pre[x] = y;
					laterSet[y] = x;
				}
			}
		}
	}

	for (ll i = 1; i <= n; i++)
		cnt[laterSet[i]]++;

	for (ll i = 1; i <= n; i++)
		if (cnt[i] == 0) {
			ll z = i;
			while (z) {
				frontInx[z] = inx;
				for (auto u:sub[z]) {
					newArr[inx++] = u;
				}
				z = laterSet[z];
			}
		}
//	for (ll i = 1; i <= n; i++) {
//		pt(frontInx[i], 1);
//	}
	build(1,1,n);
	for(ll i=1;i<=q;i++) {
//		cout<<i<<endl;
		if (arrQue[i][0] == 1) {
			ll p = oriFind(arrQue[i][1]);
			vv = -1;
			find(1, 1, n, frontInx[p], frontInx[p] + size[p] - 1);
			pt(vv, 2);
			tree[pos]=0;
			if (vv != 0) {
				pos /= 2;
				while (pos) {
					up(pos);
					pos /= 2;
				}
			}
		}
		else {
			if (used[i])
				continue;
			else {
				pre[oldInx[i][0]] = oldInx[i][0];
				pre[oldInx[i][1]] = oldInx[i][1];
				size[oldInx[i][0]] = oldSize[i][0];
				size[oldInx[i][1]] = oldSize[i][1];
			}
		}
	}

//	for (ll i = 1; i <= n; i++) {
//		pt(frontInx[i], 1);
//		pt(size[i], 2);
//	}
	return 0;
}

    /**   Created by: Humberto Yusta
          Codeforces User: humbertoyusta
          Country: Cuba
          Copyright��                    */
#include<bits/stdc++.h>
using namespace std;
/// Pragmas:
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline") //Optimization flags
//#pragma GCC option("arch=native","tune=native","no-zero-upper") //Enable AVX
//#pragma GCC target("avx2") //Enable AVX
/// Macros:
//#define int long long
#define f first
#define s second
#define db(x) cerr << #x << ": " << (x) << '\n';
#define pb push_back
#define lb lower_bound
#define up upper_bound
#define all(x) x.begin() , x.end()
#define rall(x) x.rbegin() , x.rend()
#define enl '\n'
typedef pair<int,int> ii;
typedef long double ld;
typedef unsigned long long ull;
/// Constraints:
const int maxn = 200010;
const int mod = 1000000007;
const ld eps = 1e-9;
const int inf = ((1ll<<31ll)-1ll);
const int INF = 1ll + mod + mod;
const ld pi = acos(-1);
/// Prime Numbers:
// 2, 173, 179, 181, 197, 311, 331, 737, 1009, 2011, 2027, 3079, 4001, 10037, 10079, 20011, 20089;
// 100003, 100019, 100043, 200003, 200017, 1000003, 1000033, 1000037, 1000081;
// 2000003, 2000029, 2000039, 1000000007, 1000000021, 2000000099;
/// rng
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
/// Functions:
#define lg2(x) 31 - __builtin_clz(x)
#define lgx(x,b) ( log(x) / log(b) )
/// Red-Black Tree Template ---------------------------------
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
//using namespace __gnu_pbds;
//typedef tree < long long ,  null_type ,  less<long long> ,  rb_tree_tag ,  tree_order_statistics_node_update > ordered_set;
/// Quick Pow------------------------------------------------
int qpow(int b,int e){
    if( !e ) return 1;
    if( e & 1 ) return qpow(b,e-1) * b % mod;
    int pwur = qpow(b,e>>1);
    return pwur * pwur % mod;
}
int modinv(int x){
    return qpow(x,mod-2);
}
/// My Code -------------------------------------------------

struct node{
    int val, lazy, l, r;
};

int n, tl[maxn], tr[maxn], par[maxn], ran[maxn], cnt, m, q, pt[maxn];
int lv[maxn], a[maxn], id[maxn], ind[maxn], tpid[maxn], used[maxn], mk[maxn];
vector<int> vnod[maxn], g[maxn];
vector<node> st[maxn];
pair<ii,ii> edge[300005];
pair<int,ii> nedges[300005];
ii queries[500005];

int find_(int x){
    return ( par[x] == x ) ? ( x ) : ( find_( par[x] ) );
}

void union_(int u,int v,int id){
    int a = find_(u), b = find_(v);
    if( a == b ) return;
    if( ran[a] < ran[b] ){
        swap( a , b );
        swap( u , v );
    }
    par[b] = a;
    ran[a] += ran[b];
    g[a].pb(b);
    g[b].pb(a);
    nedges[id].s.f = a;
    nedges[id].s.s = b;
    used[id] = 1;
}

void dfs(int u,int p){
    tl[u] = tr[u] = ++cnt;
    vnod[u].pb(tl[u]);
    for( auto v : g[u] ){
        if( v == p ) continue;
        lv[v] = lv[u] + 1;
        pt[v] = u;
        dfs(v,u);
        //tl[u] = min( tl[u] , tl[v] );
        tr[u] = max( tr[u] , tr[v] );
        for( auto i : vnod[v] )
            vnod[u].pb(i);
    }
}

void dfs2(int u,int p,int r,int t){
    mk[u] = r;
    for( auto v : g[u] ){
        if( v == p ) continue;
        if( ind[v] < t ) continue;
        dfs2(v,u,r,t);
    }
}

void lazyp(int sgt,int nod,int l,int r){
    st[sgt][nod].val = st[sgt][nod].lazy;
    if( l != -1 || r != -1 ){
        st[sgt][l].lazy = st[sgt][nod].lazy;
        st[sgt][r].lazy = st[sgt][nod].lazy;
    }
    st[sgt][nod].lazy = 0;
}

void build(int SgT,int nod,int l,int r){

    if( l == r ){
        if( mk[tpid[vnod[SgT][l]]] == SgT )
            st[SgT][nod].val = a[tpid[vnod[SgT][l]]];
        return;
    }

    int mi = ( l + r ) >> 1;

        if( l < mi ){
            st[SgT].pb({0,0,-1,-1});
            st[SgT][nod].l = (int)st[SgT].size() - 1;
            build(SgT,st[SgT][nod].l,l,mi);
        }

        if( mi + 1 < r ){
            st[SgT].pb({0,0,-1,-1});
            st[SgT][nod].r = (int)st[SgT].size() - 1;
            build(SgT,st[SgT][nod].r,mi+1,r);
        }

    int lft = 0;
    if( l < mi ) lft = st[SgT][st[SgT][nod].l].val;
        else{
            if( mk[tpid[vnod[SgT][l]]] == SgT )
                lft = a[tpid[vnod[SgT][l]]];
        }

    int rgt = 0;
    if( mi + 1 < r ) rgt = st[SgT][st[SgT][nod].r].val;
        else{
            if( mk[tpid[vnod[SgT][r]]] == SgT )
                rgt = a[tpid[vnod[SgT][r]]];
        }

    st[SgT][nod].val = max( lft , rgt );
    //db(st[SgT][nod].val)db(l)db(r)db(lft)db(rgt)
}

void update(int sgt,int nod,int l,int r,int x,int y,int val){

    if( st[sgt][nod].lazy ) lazyp(sgt,nod,st[sgt][nod].l,st[sgt][nod].r);

    if( l > y || r < x ) return;

    if( l >= x && r <= y ){
        if( l == r ) return;
        st[sgt][nod].lazy = val;
        lazyp(sgt,nod,st[sgt][nod].l,st[sgt][nod].r);
        return;
    }

    int mi = ( l + r ) >> 1;
        if( l < mi ) update(sgt,st[sgt][nod].l,l,mi,x,y,val);
        if( mi + 1 < r ) update(sgt,st[sgt][nod].r,mi+1,r,x,y,val);

    int lft = 0;
    if( l < mi ) lft = st[sgt][st[sgt][nod].l].val;
        else{
            if( mk[tpid[vnod[sgt][l]]] == sgt )
                lft = a[tpid[vnod[sgt][l]]];
        }

    int rgt = 0;
    if( mi + 1 < r ) rgt = st[sgt][st[sgt][nod].r].val;
        else{
            if( mk[tpid[vnod[sgt][r]]] == sgt )
                rgt = a[tpid[vnod[sgt][r]]];
        }

    st[sgt][nod].val = max( lft , rgt );
}

int query(int sgt,int nod,int l,int r,int x,int y){

    if( st[sgt][nod].lazy ) lazyp(sgt,nod,st[sgt][nod].l,st[sgt][nod].r);

    if( l > y || r < x ) return 0;

    if( l >= x && r <= y ){
        if( l != r ) return st[sgt][nod].val;
        return a[tpid[vnod[sgt][l]]] * ( mk[tpid[vnod[sgt][l]]] == sgt );
    }

    int mi = ( l + r ) >> 1;
        int aa = query(sgt,st[sgt][nod].l,l,mi,x,y);
        int bb = query(sgt,st[sgt][nod].r,mi+1,r,x,y);

    return max( aa , bb );
}

int32_t main(){
    ios_base::sync_with_stdio(0); cin.tie(0);
    cout.setf(ios::fixed); cout.precision(0);
    srand(time(NULL));

    //freopen("a.in","r",stdin);
    //freopen("a.out","w",stdout);

    cin >> n >> m >> q;

    for(int i=1; i<=n; i++){
        cin >> a[i];
        id[a[i]] = i;
    }

    for(int i=1; i<=m; i++){
        cin >> edge[i].s.f >> edge[i].s.s;
        edge[i].f.f = mod;
        edge[i].f.s = i;
    }

    for(int i=1; i<=q; i++){
        cin >> queries[i].f >> queries[i].s;
        if( queries[i].f == 2 ){
            edge[queries[i].s].f.f = i;
        }
    }

    for(int i=1; i<=m; i++)
        nedges[i] = { edge[i].f.f , { edge[i].s.f , edge[i].s.s } };

    sort(edge+1,edge+m+1);
    reverse(edge+1,edge+m+1);

    for(int i=1; i<=n; i++){
        ran[i] = i;
        par[i] = i;
    }

    for(int i=1; i<=m; i++){
        union_(edge[i].s.f,edge[i].s.s,edge[i].f.s);
    }

    for(int i=1; i<=n; i++){
        if( !tl[i] ){
            lv[i] = 1;
            dfs(i,i);
        }
        tpid[tl[i]] = i;
    }

    for(int i=1; i<=n; i++){
        if( lv[i] == 1 ){
            st[i].pb({0,0,-1,-1});
            dfs2(i,i,i,0);
            build(i,0,0,(int)vnod[i].size()-1);
        }
    }

    for(int i=1; i<=m; i++){
        if( used[i] ){
            //db(nedges[i].s.f)db(lv[nedges[i].s.f])
            //db(nedges[i].s.s)db(lv[nedges[i].s.s])
            //db(nedges[i].f)
            if( lv[nedges[i].s.f] + 1 == lv[nedges[i].s.s] ){
                ind[nedges[i].s.s] = nedges[i].f;
            }
            if( lv[nedges[i].s.s] + 1 == lv[nedges[i].s.f] ){
                ind[nedges[i].s.f] = nedges[i].f;
            }
        }
    }

    //for(int i=1; i<=n; i++){
    //    db(ind[i])
    //}
    //for(int i=1; i<=n; i++){
    //    db(i)
    //    for( auto j : vnod[i])
    //        db(j)
    //}

    for(int i=1; i<=q; i++){
        if( queries[i].f == 1 ){
            int u = queries[i].s;
            while( ind[u] >= i && pt[u] > 0 )
                u = pt[u];
            //db(u)
            int qt;
            if( vnod[u].size() > 1 ) qt = query(u,0,0,(int)vnod[u].size()-1,0,(int)vnod[u].size()-1);
            if( vnod[u].size() == 1 ){ qt = a[tpid[vnod[u][0]]]; }
            cout << qt << '\n';
            a[id[qt]] = 0;
            int nid = lower_bound(all(vnod[u]),tl[id[qt]]) - vnod[u].begin();
            update(u,0,0,(int)vnod[u].size()-1,nid,nid,0);
        }
        if( queries[i].f == 2 ){

            int u = nedges[queries[i].s].s.f;
            int v = nedges[queries[i].s].s.s;

            if( lv[u] > lv[v] ) swap(u,v);

            if( !used[queries[i].s] ) continue;

            while( ind[u] >= i && pt[u] > 0 )
                u = pt[u];
            int nid = lower_bound(all(vnod[u]),tl[v]) - vnod[u].begin();
            int nid2 = lower_bound(all(vnod[u]),tr[v]+1) - vnod[u].begin();
            //db(nid)db(nid2-1)db(v)db(tl[v])db(tr[v])

            st[v].pb({0,0,-1-1});
            dfs2(v,pt[v],v,i);
            build(v,0,0,(int)vnod[v].size()-1);

            update(u,0,0,(int)vnod[u].size()-1,nid,nid2-1,0);
        }
    }

    return 0;
}