#include "bits/stdc++.h" using namespace std; #define FOR(i,j,k) for(int (i)=(j);(i)<(int)(k);++(i)) #define rep(i,j) FOR(i,0,j) #define each(x,y) for(auto &(x):(y)) #define mp make_pair #define mt make_tuple #define all(x) (x).begin(),(x).end() #define debug(x) cout<<#x<<": "<<(x)< pii; typedef vector vi; typedef vector vll; class TwoEdgeCC { public: TwoEdgeCC(vector > &G) :V((int)G.size()), now(0), disc(V), low(V) { for (int i = 0; i < V; ++i) { if (!disc[i]) { dfs(G, i, -1); } } if (stk.size()) { tecc.push_back(vector()); do { tecc.back().push_back(stk.top()); stk.pop(); } while (stk.size()); } } vector > getBridges() { return move(bridges); } vector> get() { return move(tecc); } private: int V, now; vector disc, low; vector > bridges; stack stk; vector> tecc; void dfs(const vector > &G, int u, int parent) { disc[u] = ++now; low[u] = now; stk.push(u); for (int i = 0; i < (int)G[u].size(); ++i) { int v = G[u][i]; if (!disc[v]) { dfs(G, v, u); low[u] = min(low[u], low[v]); if (disc[u] < low[v]) { int x = u, y = v; if (x > y)swap(x, y); bridges.emplace_back(x, y); int w; tecc.push_back(vector()); do { w = stk.top(); tecc.back().push_back(w); stk.pop(); } while (w != v); } } else if (v != parent) { low[u] = min(low[u], disc[v]); } } } }; class HLDecomposition { int cur = 0; void bfs(const vector > &G) { queue > que; vector order; que.push(make_tuple(0, -1, 0)); while (!que.empty()) { int u, pre, d; tie(u, pre, d) = que.front(); que.pop(); parent[u] = pre; depth[u] = d; order.push_back(u); for (int v : G[u])if (v != pre) { que.push(make_tuple(v, u, d + 1)); } } reverse(order.begin(), order.end()); for (int u : order) { sub[u] = 1; for (int v : G[u])if (v != parent[u])sub[u] += sub[v]; } } void dfs_stk(const vector > & G) { stack > stk; stk.push(make_pair(0, 0)); while (!stk.empty()) { int u, h, pre; tie(u, h) = stk.top(); stk.pop(); head[u] = h; id[u] = cur++; pre = parent[u]; int heavy = -1, maxi = 0; for (int v : G[u]) { if (v != pre && maxi < sub[v]) { maxi = sub[v]; heavy = v; } } for (int v : G[u]) { if (v != pre&&v != heavy) { stk.push(make_pair(v, v)); } } if (heavy != -1)stk.push(make_pair(heavy, h)); } } public: vector parent, depth, sub, id, head; HLDecomposition(const vector > &G) { parent = depth = sub = id = head = vector(G.size()); bfs(G); dfs_stk(G); } /* パス(u, v)を半開区間の集合に変換する。 O(log(|V|)) */ vector > goUpToLCA(int u, int v) { vector > res; while (true) { if (head[u] == head[v]) { if (depth[u] > depth[v])swap(u, v); res.emplace_back(id[u], id[v] + 1); break; } else { if (depth[head[u]] > depth[head[v]])swap(u, v); res.emplace_back(id[head[v]], id[v] + 1); v = parent[head[v]]; } } return res; } }; template class DynamicRMQ { int n; Val init; vector dat; Cmp cmp; inline Val query(int a, int b, int k, int l, int r) { if (r <= a || b <= l) return init; if (a <= l&&r <= b) return dat[k]; else { Val vl, vr; vl = query(a, b, k << 1, l, (l + r) >> 1); vr = query(a, b, (k << 1) | 1, (l + r) >> 1, r); return cmp(vl, vr) ? vl : vr; } } public: DynamicRMQ() {} DynamicRMQ(int n_, Val init_) :n(1), init(init_) { for (; n(n << 1, init); } void update(int k, Val a) { k += n; dat[k] = a; while (k > 1) { k >>= 1; dat[k] = cmp(dat[k << 1], dat[(k << 1) | 1]) ? dat[k << 1] : dat[(k << 1) | 1]; } } Val query(int a, int b) { return query(a, b, 1, 0, n); } }; typedef DynamicRMQ > RMinQ64; typedef DynamicRMQ > RMaxQ64; typedef DynamicRMQ > RMinQ32; typedef DynamicRMQ > RMaxQ32; int main(){ ios::sync_with_stdio(false); cin.tie(0); int N, M, Q; cin >> N >> M >> Q; vector G(N); rep(i, M) { int a, b; cin >> a >> b; --a; --b; G[a].push_back(b); G[b].push_back(a); } auto tecc = TwoEdgeCC(G).get(); vi id(N); rep(i, sz(tecc)) { each(j, tecc[i]) { id[j] = i; } } int K = sz(tecc); vector H(K); rep(i, N)each(j, G[i]) { int u = id[i], v = id[j]; if (u != v) { H[u].push_back(v); } } auto hl = HLDecomposition(H); RMaxQ32 rmq(K, -1); unordered_map pos; vector> vals(K); while (Q--) { int t, x, y; cin >> t >> x >> y; if (t == 1) { x = hl.id[id[x-1]]; vals[x].insert(y); rmq.update(x, *vals[x].rbegin()); pos[y] = x; } else { x = hl.id[id[x - 1]], y = hl.id[id[y - 1]]; auto path = hl.goUpToLCA(x, y); int ans = -1; each(p, path) { smax(ans, rmq.query(p.first, p.second)); } cout << ans << endl; if (ans != -1) { int p = pos[ans], z = -1; vals[p].erase(ans); if (sz(vals[p]))z = *vals[p].rbegin(); rmq.update(p, z); } } } }