#include int ri() { int n; scanf("%d", &n); return n; } struct TwoDecomp { std::vector > hen; TwoDecomp (const std::vector > &hen) : hen(hen) {} std::vector low, ord; std::vector used; std::vector > bridges; int dfs_cnt = 0; void dfs1(int i, int prev) { ord[i] = dfs_cnt++; low[i] = ord[i]; for (auto j : hen[i]) { if (!used[j]) { used[j] = true; dfs1(j, i); low[i] = std::min(low[i], low[j]); if (low[j] > ord[i]) bridges.push_back({i, j}); } else if (j != prev) low[i] = std::min(low[i], low[j]); } } std::vector group; int group_cnt = 0; void dfs2(int i, int prev) { if (prev != -1 && low[i] <= ord[prev]) group[i] = group[prev]; else group[i] = group_cnt++; for (auto j : hen[i]) if (group[j] == -1) dfs2(j, i); } std::pair, std::vector > > decomp() { int n = hen.size(); low.resize(n); ord.resize(n); used.resize(n); used[0] = true; dfs1(0, -1); group.resize(n, -1); dfs2(0, -1); std::vector > new_hen(group_cnt); for (auto i : bridges) { new_hen[group[i.first]].push_back(group[i.second]); new_hen[group[i.second]].push_back(group[i.first]); } return {group, new_hen}; } }; struct SegTree { std::vector > leaf; std::vector > max; int n; SegTree () = default; SegTree (int n_) { for (n = 1; n < n_; n <<= 1); leaf.resize(n); max.resize(n << 1, {-1, -1}); } void push(int i, int val) { leaf[i].push(val); for (max[i + n] = {leaf[i].size() ? leaf[i].top() : -1, i}, i += n; i >>= 1; ) max[i] = std::max(max[i << 1], max[i << 1 | 1]); } int pop(int i) { int val = leaf[i].top(); leaf[i].pop(); for (max[i + n] = {leaf[i].size() ? leaf[i].top() : -1, i}, i += n; i >>= 1; ) max[i] = std::max(max[i << 1], max[i << 1 | 1]); return val; } std::pair get_max(int l, int r) { int val = -1, index = -1; for (l += n, r += n; l < r; l >>= 1, r >>= 1) { if (r & 1) { r--; if (val < max[r].first) val = max[r].first, index = max[r].second; } if (l & 1) { if (val < max[l].first) val = max[l].first, index = max[l].second; l++; } } return {index, val}; } }; struct HLDecomp { std::vector > hen; HLDecomp (const std::vector > &hen) : hen(hen) {} std::vector size, parent; void dfs1(int i, int prev) { parent[i] = prev; if (prev != -1) hen[i].erase(std::find(hen[i].begin(), hen[i].end(), prev)); for (auto &j : hen[i]) { dfs1(j, i); size[i] += size[j]; if (size[j] > size[hen[i][0]]) std::swap(j, hen[i][0]); } } std::vector top, chain, depth_local, chain_sizes{0}; void dfs2(int i) { chain[i] = chain_sizes.size() - 1; depth_local[i] = chain_sizes.back()++; for (auto j : hen[i]) { if (j == hen[i][0]) top[j] = top[i]; else top[j] = j, chain_sizes.push_back(0); dfs2(j); } } std::vector trees; void decomp() { int n = hen.size(); size.resize(n, 1); parent.resize(n); dfs1(0, -1); top.resize(n); chain.resize(n); depth_local.resize(n); dfs2(0); int m = chain_sizes.size(); trees.resize(m); for (int i = 0; i < m; i++) trees[i] = SegTree(chain_sizes[i]); } void push(int i, int val) { trees[chain[i]].push(depth_local[i], val); } int pop(int i, int j) { int max = -1, max_chain = -1, max_depth = -1; while (chain[i] != chain[j]) { if (chain[i] > chain[j]) std::swap(i, j); auto tmp = trees[chain[j]].get_max(0, depth_local[j] + 1); if (max < tmp.second) max = tmp.second, max_chain = chain[j], max_depth = tmp.first; j = parent[top[j]]; } if (depth_local[i] > depth_local[j]) std::swap(i, j); auto tmp = trees[chain[i]].get_max(depth_local[i], depth_local[j] + 1); if (max < tmp.second) max = tmp.second, max_chain = chain[i], max_depth = tmp.first; if (max == -1) return -1; trees[max_chain].pop(max_depth); return max; } }; int main() { int n = ri(), m = ri(), q = ri(); std::vector > org_hen(n); for (int i = 0; i < m; i++) { int a = ri() - 1; int b = ri() - 1; org_hen[a].push_back(b); org_hen[b].push_back(a); } TwoDecomp two_decomper(org_hen); auto decomped = two_decomper.decomp(); auto group = decomped.first; auto hen = decomped.second; HLDecomp hl_decomper(hen); hl_decomper.decomp(); for (int i = 0; i < q; i++) { int t = ri(); int x = ri(); int y = ri(); if (t == 1) hl_decomper.push(group[x - 1], y); else printf("%d\n", hl_decomper.pop(group[x - 1], group[y - 1])); } return 0; }