using System; using System.IO; using System.Linq; using System.Text; using System.Collections.Generic; using System.Diagnostics; using Enu = System.Linq.Enumerable; public class Program { public class XorShift { uint m = 2463534242; public XorShift(int seed = 0) { if (seed != 0) m = (uint)seed; } public uint NextU() { m ^= m << 13; m ^= m >> 17; return m ^= m << 5; } public int Next() { return (int)(NextU() & int.MaxValue); } public int Next(int max) { return max <= 0 ? 0 : (int)(NextU() % (uint)max); } public int Next(int min, int max) { return min + Next(max - min); } public double NextDouble() { return (double)NextU() / uint.MaxValue; } } public void Solve() { int N = Reader.Int(), M = Reader.Int(), NQ = Reader.Int(); var E = Reader.IntTable(M); var Q = Reader.IntTable(NQ); var comp = new TwoEdgeConnectedComponent(N, E, 1); var hld = new HLDecomposition(comp.Count, comp.ComponentEdges); var seg = hld.Path.Select(p => new MaxHeapSegmentTree(p.Count)).ToArray(); var ans = new List(); foreach (var q in Q) if (q[0] == 1) { int v = comp.VtoComponentId(q[1] - 1), val = q[2]; seg[hld.Y[v]].Add(hld.X[v], val); } else { int a = comp.VtoComponentId(q[1] - 1), b = comp.VtoComponentId(q[2] - 1); int maxVal = -1, pathId = 0, index = 0; Action Pop = (p, L, R) => { int v, i; v = seg[p].Max(out i, L, R); if (v > maxVal) { pathId = p; maxVal = v; index = i; } }; hld.Query(a, b, Pop); Console.WriteLine(maxVal); if (maxVal >= 0) seg[pathId].PopAt(index); } if (ans.Count > 0) Console.WriteLine(string.Join("\n", ans)); } } public class Component { public List Vertexes; public int[] Edges; public Component(List vs) { Vertexes = vs; } } public class TwoEdgeConnectedComponent { int N, id; List[] E; int[] VtoCompId, order; bool[] inS; Stack S = new Stack(), roots = new Stack(); List Components = new List(); HashSet BridgesSet = new HashSet(); public List Bridges = new List(); public int[][] ComponentEdges; public int Count { get { return Components.Count; } } public Component this[int i] { get { return Components[i]; } } public bool IsBridge(int a, int b) { return BridgesSet.Contains(ToKey(a, b)); } public int VtoComponentId(int v) { return VtoCompId[v]; } public bool SameComponent(int a, int b) { return VtoCompId[a] == VtoCompId[b]; } public TwoEdgeConnectedComponent(int N) { Init(N); } public TwoEdgeConnectedComponent(int N, int[][] E, int origin = 0) { Init(N); Array.ForEach(E, e => AddEdge(e[0] - origin, e[1] - origin)); Decompose(); } void Init(int N) { this.N = N; VtoCompId = new int[N]; order = new int[N]; inS = new bool[N]; E = new List[N]; for (int i = 0; i < N; i++) E[i] = new List(); } public void AddEdge(int a, int b) { E[a].Add(b); E[b].Add(a); } public void Decompose() { for (int i = 0; i < N; i++) if (order[i] == 0) DFS(i); CheckEdges(); } void CheckEdges() { Bridges.Sort((a, b) => a[0] != b[0] ? a[0] - b[0] : a[1] - b[1]); var es = new List(); for (int compId = 0; compId < Count; compId++) { var comp = Components[compId]; var set = new HashSet(); foreach (int a in comp.Vertexes) foreach (int b in E[a]) if (VtoCompId[a] != VtoCompId[b]) set.Add(VtoCompId[b]); comp.Edges = set.ToArray(); Array.Sort(comp.Edges); foreach (int b in comp.Edges) if (compId < b) es.Add(new[] { compId, b }); } ComponentEdges = es.ToArray(); } void DFS(int start) { var stack = new Stack(); stack.Push(-1); stack.Push(start); for (; stack.Count > 0; ) { int v = stack.Pop(), prev = stack.Pop(); if (v < 0) { v = ~v; foreach (int next in E[v]) if (next != prev && inS[next]) while (order[roots.Peek()] > order[next]) roots.Pop(); if (roots.Peek() != v) continue; if (prev != -1) AddBridge(prev, v); AddComponent(prev, v); } else { if (order[v] != 0) continue; stack.Push(prev); stack.Push(~v); order[v] = ++id; roots.Push(v); S.Push(v); inS[v] = true; foreach (int next in E[v]) if (order[next] == 0) { stack.Push(v); stack.Push(next); } } } } void AddBridge(int a, int b) { BridgesSet.Add(ToKey(a, b)); Bridges.Add(new[] { Math.Min(a, b), Math.Max(a, b) }); } void AddComponent(int prev, int root) { int compId = Components.Count; var vs = new List(); for (; ; ) { int v = S.Pop(); inS[v] = false; VtoCompId[v] = compId; vs.Add(v); if (v == root) break; } vs.Sort(); Components.Add(new Component(vs)); roots.Pop(); } long ToKey(long a, long b) { return a < b ? a * N + b : b * N + a; } } public class HLDecomposition { int N; List[] E; public int[] Y, X, Size, Parent, Up, UnderL, UnderR; public List> Path = new List>(); List PathDepth = new List(); // F(pathId, L, R) public void Query(int a, int b, Action F) { for (int at = Y[a], L = 0, R, na = a, nb = b; a != -1; a = na, b = nb) { if (Y[a] == Y[b]) { at = Y[a]; L = Math.Min(X[a], X[b]); R = Math.Max(X[a], X[b]); na = -1; } else if (PathDepth[Y[a]] >= PathDepth[Y[b]]) { at = Y[a]; L = 0; R = X[a]; na = Up[a]; } else { at = Y[b]; L = 0; R = X[b]; nb = Up[b]; } F(at, L, R + 1); } } public HLDecomposition(int N) { Init(N); } public HLDecomposition(int N, int[][] E, int origin = 0) { Init(N); Array.ForEach(E, e => AddEdge(e[0] - origin, e[1] - origin)); Build(); } void Init(int N) { this.N = N; Y = new int[N]; X = new int[N]; Size = new int[N]; Parent = new int[N]; Up = new int[N]; UnderL = new int[N]; UnderR = new int[N]; E = new List[N]; for (int i = 0; i < N; i++) E[i] = new List(); } public void AddEdge(int a, int b) { E[a].Add(b); E[b].Add(a); } public void Build() { CountNodes(); CompressPath(); } void CountNodes() { var stack = new Stack(); var nodes = new int[N]; int ni = N - 1; stack.Push(0); while (stack.Count > 0) { int a = stack.Pop(); for (int ei = 0; ei < E[a].Count; ei++) { int b = E[a][ei]; if (b == Parent[a]) { E[a].RemoveAt(ei); ei--; } else { Parent[b] = a; stack.Push(b); } } nodes[ni--] = a; } foreach (int a in nodes) { Size[a] = 1; var e = E[a]; for (int i = 0; i < e.Count; i++) { int b = e[i]; Size[a] += Size[b]; if (Size[b] > Size[e[0]]) { int t = e[0]; e[0] = b; e[i] = t; } } } } void CompressPath() { var stack = new Stack(); stack.Push(0); while (stack.Count > 0) { int a = stack.Pop(); if (a < 0) { UnderR[~a] = Path.Count; continue; } if (X[a] == 0) { Path.Add(new List()); PathDepth.Add(a == 0 ? 0 : PathDepth[Y[Parent[a]]] + 1); } int pathId = Y[a] = Path.Count - 1; Path[pathId].Add(a); Up[a] = Parent[Path[pathId][0]]; UnderL[a] = Path.Count; stack.Push(~a); if (E[a].Count == 0) continue; for (int i = E[a].Count - 1; i > 0; i--) stack.Push(E[a][i]); X[E[a][0]] = X[a] + 1; stack.Push(E[a][0]); } } public int LCA(int a, int b) { if (Y[a] == Y[b]) return (X[a] < X[b]) ? a : b; if (PathDepth[Y[a]] >= PathDepth[Y[b]]) return LCA(Parent[Path[Y[a]][0]], b); return LCA(a, Parent[Path[Y[b]][0]]); } public int Dist(int a, int b) { if (Y[a] == Y[b]) return Math.Abs(X[a] - X[b]); if (PathDepth[Y[a]] >= PathDepth[Y[b]]) return X[a] + 1 + Dist(Parent[Path[Y[a]][0]], b); return X[b] + 1 + Dist(a, Parent[Path[Y[b]][0]]); } } public class MaxHeapSegmentTree { static readonly long[] Q = new long[100]; public readonly int N; readonly int[] Val; readonly int[] Who; readonly HeapMax[] heap; public MaxHeapSegmentTree(int n) { for (N = 2; N < n; ) N *= 2; heap = new HeapMax[N]; Val = new int[N * 2]; Who = new int[N * 2]; for (int i = 0; i < N; i++) { heap[i] = new HeapMax(2); heap[i].Push(int.MinValue); Who[N + i] = i; } for (int i = 0; i < Val.Length; i++) Val[i] = int.MinValue; } public void Add(int index, int val) { heap[index].Push(val); int i = index + N; Val[i] = heap[index].Peek(); for (i >>= 1; i > 0; i >>= 1) if (Val[i << 1] >= Val[i << 1 | 1]) { Val[i] = Val[i << 1]; Who[i] = Who[i << 1]; } else { Val[i] = Val[i << 1 | 1]; Who[i] = Who[i << 1 | 1]; } } public int Max(int L = 0, int R = int.MaxValue) { int d; return Max(out d, L, R); } public int Max(out int index, int L = 0, int R = int.MaxValue) { index = -1; int res = int.MinValue; Q[0] = 1L << 32; for (int s = 0, t = 1, len = N, first = 1; s != t; ++s) { int i = (int)(Q[s] >> 32), a = (int)Q[s]; if (s == first) { len >>= 1; first = t; } if (Val[i] < res || Val[i] == res && Who[i] > index) continue; if (a >= L && a + len <= R) { res = Val[i]; index = Who[i]; continue; } int mid = a + (len >> 1); if (L < mid) Q[t++] = ((long)(i << 1) << 32) + a; if (R > mid) Q[t++] = ((long)(i << 1 | 1) << 32) + mid; } return res; } public int Pop(int L = 0, int R = int.MaxValue) { int index; int maxVal = Max(out index, L, R); return PopAt(index); } public int PopAt(int index) { int val = heap[index].Pop(); int i = index + N; Val[i] = heap[index].Peek(); for (i >>= 1; i > 0; i >>= 1) if (Val[i << 1] >= Val[i << 1 | 1]) { Val[i] = Val[i << 1]; Who[i] = Who[i << 1]; } else { Val[i] = Val[i << 1 | 1]; Who[i] = Who[i << 1 | 1]; } return val; } } public class HeapMax { int[] A; public HeapMax(int size = 1000) { A = new int[size]; } public int Count { get; private set; } public int Peek() { return A[1]; } public void Push(int val) { int i = ++Count; if (i == A.Length) Array.Resize(ref A, A.Length * 2); for (; i > 1 && val > A[i >> 1]; i >>= 1) A[i] = A[i >> 1]; A[i] = val; } public int Pop() { int res = A[1], val = A[Count--]; if (Count == 0) return res; int i = 1; for (int L = i << 1; L <= Count; L = i << 1) { if (L + 1 <= Count && A[L + 1] > A[L]) L++; if (A[L] > val) { A[i] = A[L]; i = L; } else break; } A[i] = val; return res; } } class Entry { static void Main() { new Program().Solve(); } } class Reader { static TextReader reader = Console.In; static readonly char[] separator = { ' ' }; static readonly StringSplitOptions op = StringSplitOptions.RemoveEmptyEntries; static string[] A = new string[0]; static int i; static void Init() { Dispose(); A = new string[0]; } public static void Set(TextReader r) { Init(); reader = r; } public static void Set(string file) { Init(); reader = new StreamReader(file); } public static bool HasNext() { return CheckNext(); } public static string String() { return Next(); } public static int Int() { return int.Parse(Next()); } public static long Long() { return long.Parse(Next()); } public static double Double() { return double.Parse(Next()); } public static int[] IntLine() { return Array.ConvertAll(Split(Line()), int.Parse); } public static int[] IntArray(int N) { return Range(N, Int); } public static int[][] IntTable(int H) { return Range(H, IntLine); } public static string[] StringArray(int N) { return Range(N, Next); } public static string[][] StringTable(int N) { return Range(N, () => Split(Line())); } public static string Line() { return reader.ReadLine().Trim(); } public static T[] Range(int N, Func f) { var r = new T[N]; for (int i = 0; i < N; r[i++] = f()) ; return r; } public static void Dispose() { reader.Dispose(); } static string[] Split(string s) { return s.Split(separator, op); } static string Next() { CheckNext(); return A[i++]; } static bool CheckNext() { if (i < A.Length) return true; string line = reader.ReadLine(); if (line == null) return false; if (line == "") return CheckNext(); A = Split(line); i = 0; return true; } }