import java.util.*;
import java.io.*;

public class Main {

	BufferedReader in;
	StringTokenizer str = null;
	PrintWriter out;

	private String next() throws Exception{
		while (str == null || !str.hasMoreElements())
			str = new StringTokenizer(in.readLine());
		return str.nextToken();
	}

	private int nextInt() throws Exception{
		return Integer.parseInt(next());
	}

	private long nextLong() throws Exception{
		return Long.parseLong(next());
	}

	private double nextDouble() throws Exception{
		return Double.parseDouble(next());
	}

	List<Integer> []g;
	int n,m,query;
	int []p, d;
	boolean []used;

	public void run() throws Exception{
		in =  new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		n = nextInt();
		m = nextInt();
		query = nextInt();
		p = new int[n];
		d = new int[n];
		for(int i=1;i<n;i++) p[i] = i;
		g = new LinkedList[n];
		for(int i=0;i<n;i++) g[i] = new LinkedList<Integer>();
		for(int i=0;i<m;i++){
			int v = nextInt()-1, u = nextInt()-1;
			g[v].add(u);
			g[u].add(v);
		}

		used = new boolean[n];
		dis = new int[n];
		q = new int[n];
		for(int i=0;i<n;i++){
			if (!used[i]) {
				d[i] = bfs(i, 0);
			}
		}
		// System.out.println(Arrays.toString(d));

		for(int cs=0;cs<query;cs++){
			int type = nextInt();
			int x = nextInt()-1;
			if (type == 1) {
				int id = find(x);
				out.println(d[id]);
			}else {
				int y = nextInt()-1;
				int id1 = find(x);
				int id2 = find(y);
				if (id1 == id2) continue;
				union(id1, id2);
				// System.out.println("new query");
				// System.out.println(id1 + " " + id2);
				// System.out.println(d[id1] + " " + d[id2]);
				d[id1] = max(d[id1], d[id2], (int)Math.ceil(1.*d[id1]/2)+(int)Math.ceil(1.*d[id2]/2)+1);
				// System.out.println("new diametr = " + d[id1]);

			}
		}

		out.close();
	}

	private int max(int ...a) {
		int max = a[0];
		for(int i=1;i<a.length;i++) max = Math.max(max, a[i]);
		return max;
	}

	int []dis, q;
	final static int oo = Integer.MAX_VALUE/2;

	private int bfs(int x, int times) {
		int tail = 0, head = 0;
		q[tail++] = x;
		int superParent = x;

		Arrays.fill(dis, oo);
		dis[x] = 0;

		while(head != tail) {
			int c = q[head++];
			used[c] = true;
			for(int i : g[c]) {
				if (times == 0) {
					p[x] = superParent;
				}
				if (dis[i] > dis[c] + 1) {
					dis[i] = dis[c] + 1;
					q[tail++] = i;
				}
			}
		}
		int v = x;
		for(int i=0;i<tail;i++){
			if (dis[q[i]] > dis[v]) {
				v = q[i];
			}
		}
		if (times == 0) return bfs(v, times+1);
		return dis[v];
	}

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

	private void union(int a, int b) {
		a = find(a);
		b = find(b);
		p[b] = a;
	}

	public static void main(String[] args) throws Exception{
		new Main().run();
	}
}


import java.awt.Container;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;

public class Civilization {

	public static int parent[];
	public static ArrayList<Integer> graph[];

	public static int find(int i) {
		if (parent[i] == i)
			return i;
		else
			return parent[i] = find(parent[i]);
	}

	public static int dp[];

	public static void union(int x, int y) {
		x = find(x);
		y = find(y);
		if (x == y)
			return;

		dp[x] = Math.max(Math.max(dp[x], dp[y]), (dp[x] + 1) / 2 + (dp[y] + 1)
				/ 2 + 1);
		parent[y] = x;

	}

	public static int node = -1;
	public static int longest = -1;

	public static boolean vis[];

	public static void bfs(int i, int depth, int n) {
		parent[i] = n;
		vis[i] = true;

		if (longest < depth) {

			longest = depth;
			node = i;

		}

		for (int j = 0; j < graph[i].size(); j++) {
			int node2 = graph[i].get(j);
			if (!vis[node2]) {
				bfs(node2, depth + 1, n);
			}
		}

	}

	public static void main(String[] args) throws IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder qq = new StringBuilder();
		PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

		String y[] = in.readLine().split(" ");
		int n = Integer.parseInt(y[0]);
		int m = Integer.parseInt(y[1]);
		int q = Integer.parseInt(y[2]);
		graph = new ArrayList[n + 1];
		parent = new int[n + 1];
		dp = new int[n + 1];
		vis = new boolean[n + 1];
		for (int i = 0; i <= n; i++) {
			graph[i] = new ArrayList();
			parent[i] = i;

		}

		for (int i = 0; i < m; i++) {
			y = in.readLine().split(" ");
			int one = Integer.parseInt(y[0]);
			int two = Integer.parseInt(y[1]);
			graph[one].add(two);
			graph[two].add(one);
		}
		for (int i = 1; i <= n; i++) {
			int p = find(i);
			if (p == i) {
				vis = new boolean[n + 1];
				bfs(i, 0, i);
				longest = -1;
				vis = new boolean[n + 1];
				bfs(node, 0, i);
				dp[p] = longest;
				longest = -1;

			}
		}
		for (int i = 0; i < q; i++) {
			y = in.readLine().split(" ");

			int on = Integer.parseInt(y[0]);
			if (on == 1)
				qq.append(dp[find(Integer.parseInt(y[1]))] + "\n");
			else
				union(Integer.parseInt(y[1]), Integer.parseInt(y[2]));

		}
		System.out.print(qq);
	}
}


import java.awt.Container;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;

public class Civilization {

	public static int parent[];
	public static ArrayList<Integer> graph[];

	public static int find(int i) {
		if (parent[i] == i)
			return i;
		else
			return parent[i] = find(parent[i]);
	}

	public static int dp[];

	public static void union(int x, int y) {
		x = find(x);
		y = find(y);
		if (x == y)
			return;

		dp[x] = Math.max(Math.max(dp[x], dp[y]), (dp[x] + 1) / 2 + (dp[y] + 1)
				/ 2 + 1);
		parent[y] = x;

	}

	public static int node = -1;
	public static int longest = -1;

	public static int ways[];

	public static void bfs(int i, int depth, int n, int w) {
		parent[i] = n;
		ways[i] = w;
		if (longest < depth) {

			longest = depth;
			node = i;

		}

		for (int j = 0; j < graph[i].size(); j++) {
			int node2 = graph[i].get(j);
			if (ways[node2] != w) {
				bfs(node2, depth + 1, n, w);
			}
		}

	}

	public static void main(String[] args) throws IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder qq = new StringBuilder();
		PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

		String y[] = in.readLine().split(" ");
		int n = Integer.parseInt(y[0]);
		int m = Integer.parseInt(y[1]);
		int q = Integer.parseInt(y[2]);
		graph = new ArrayList[n + 1];
		parent = new int[n + 1];
		dp = new int[n + 1];
		ways=new int[n+1];

		for (int i = 0; i <= n; i++) {
			graph[i] = new ArrayList();
			parent[i] = i;

		}

		for (int i = 0; i < m; i++) {
			y = in.readLine().split(" ");
			int one = Integer.parseInt(y[0]);
			int two = Integer.parseInt(y[1]);
			graph[one].add(two);
			graph[two].add(one);
		}
		for (int i = 1; i <= n; i++) {
			int p = find(i);
			if (p == i) {
				bfs(i, 0, i,1);
				longest = -1;
				bfs(node, 0, i,2);
				dp[p] = longest;
				longest = -1;

			}
		}
		for (int i = 0; i < q; i++) {
			y = in.readLine().split(" ");

			int on = Integer.parseInt(y[0]);
			if (on == 1)
				qq.append(dp[find(Integer.parseInt(y[1]))] + "\n");
			else
				union(Integer.parseInt(y[1]), Integer.parseInt(y[2]));

		}
		out.print(qq);
		out.close();
	}
}


import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class TaskE {
	//-----------MyScanner class for faster input----------
	public static class MyScanner {
		BufferedReader br;
		StringTokenizer st;

		public MyScanner(InputStream is) {
			br = new BufferedReader(new InputStreamReader(is));
		}

		String next() {
			while (st == null || !st.hasMoreElements()) {
				try {
					st = new StringTokenizer(br.readLine());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			return st.nextToken();
		}

		int nextInt() {
			return Integer.parseInt(next());
		}

		long nextLong() {
			return Long.parseLong(next());
		}

		double nextDouble() {
			return Double.parseDouble(next());
		}

		String nextLine(){
			String str = "";
			try {
				str = br.readLine();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return str;
		}

	}
	//--------------------------------------------------------
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		MyScanner in = new MyScanner(inputStream);
		PrintWriter out = new PrintWriter(new BufferedOutputStream(outputStream));
		TaskE solver = new TaskE();
		solver.solve(1, in, out);
		out.close();
	}

	final int maxn = 300500;

	int n, m, q;
	@SuppressWarnings("unchecked")
	ArrayList<Integer>[] g = (ArrayList<Integer>[])new ArrayList[maxn];
	boolean[] used = new boolean[maxn];
	int[] p = new int[maxn], sz = new int[maxn], diameter = new int[maxn];
	int maxi, maxiV;

	void dfs(int v, int depth, int p) {
		if (depth > maxi) {
			maxi = depth;
			maxiV = v;
		}
		for (int i = 0; i < g[v].size(); i++) {
			int to = g[v].get(i);
			if (to != p) dfs(to, depth + 1, v);
		}
	}

	int findLongestWay(int v) {
		maxi = -1;
		dfs(v, 0, -1);
		maxi = -1;
		dfs(maxiV, 0, -1);
		return maxi;
	}

	void init() {
		for (int i = 1; i <= n; i++) {
			p[i] = i;
			sz[i] = 1;
			diameter[i] = 0;
			g[i] = new ArrayList<>();
		}
	}

	int getSet(int v) {
		if (p[v] == v) return v;
		return p[v] = getSet(p[v]);
	}

	void unionSets1(int x, int y) {
		x = getSet(x);
		y = getSet(y);
		if (sz[x] > sz[y]) {
			int t = sz[x];
			sz[x] = sz[y];
			sz[y] = t;
		}
		sz[y] += sz[x];
		p[x] = y;
	}

	int rad(int x) {
		return (diameter[x] + 1) / 2;
	}

	void unionSets2(int x, int y) {
		x = getSet(x);
		y = getSet(y);
		if (x == y) return;
		if (sz[x] > sz[y]) {
			int t = sz[x];
			sz[x] = sz[y];
			sz[y] = t;
		}
		sz[y] += sz[x];
		p[x] = y;
		diameter[y] = Math.max(rad(x) + rad(y) + 1, Math.max(diameter[x], diameter[y]));
	}

	int query(int x) {
		return diameter[getSet(x)];
	}

	public void solve(int test, MyScanner in, PrintWriter out) {
		n = in.nextInt();
		m = in.nextInt();
		q = in.nextInt();
		init();
		for (int i = 1; i <= m; i++) {
			int x, y;
			x = in.nextInt();
			y = in.nextInt();
			g[x].add(y);
			g[y].add(x);
			unionSets1(x, y);
		}
		for (int i = 1; i <= n; i++) {
			int pp = getSet(i);
			if (!used[pp]) {
				used[pp] = true;
				diameter[pp] = findLongestWay(i);
			}
		}
		while (q-- > 0) {
			int t, x, y;
			t = in.nextInt();
			if (t == 2) {
				x = in.nextInt();
				y = in.nextInt();
				unionSets2(x, y);
			}
			else {
				x = in.nextInt();
				out.println(query(x));
			}
		}
	}

}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Civilization {

	static class DSU {
		int rank[];
		int parent[];
		int N;
		int sets;
		int setsize[];

		public DSU(int N){
			this.N = N;
			sets = N;
			parent = new int[N];
			rank = new int[N];
			setsize = new int[N];
			for(int i=0;i<N;i++){ parent[i] = i; setsize[i] = 1; }

		}

		public void union(int x,int y){
			if(isSameSet(x,y)) return;
			sets--;
			int xp = getParent(x);
			int yp = getParent(y);
			if(rank[xp]>rank[yp]){ parent[yp] = xp; setsize[xp]+=setsize[yp];}
			else{
				if(rank[xp]==rank[yp]){
					rank[yp]++;
					parent[xp] = yp;
					setsize[yp]+=setsize[xp];
				}
				else
				{ parent[xp] =yp; setsize[yp] += setsize[xp]; }
			}

		}

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

		public boolean isSameSet(int x,int y){
			return getParent(x)==getParent(y);
		}

		public int numDisjointSets(){
			return sets;
		}
		public int getSetSize(int x){
			return setsize[getParent(x)];
		}

	}

	static int leader[] = new int[3*100000+5];
	static int D[] = new int[3*100000+5];
	static boolean seen[] = new boolean[3*100000+5];
	static int N,E,q;
	static ArrayList<Integer> tree[] = new ArrayList[3*100000+5];
	static int deg[] = new int[3*100000+5];
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static StringTokenizer st;

	static class Pair
	{
		int first;
		long second;
		int parent;
		public Pair(int first, long second,int parent)
		{
			this.first = first;
			this.second = second;
			this.parent = parent;
		}
		public Pair(int first,long second)
		{
			this.first = first;
			this.second = second;
		}
	}

	static Pair bfs(int idx,int c)
	{
		Queue<Pair> Q = new LinkedList();
		Q.add(new Pair(idx,0,-1));
		long max = -1;
		int choice = Integer.MAX_VALUE-1000;
		while(!Q.isEmpty())
		{
			Pair v = Q.poll();

			leader[v.first] = c;
			seen[v.first] = true;

			if(v.second > max )
			{
				max = v.second;
				choice = v.first;
			}

			for(Integer x:tree[v.first])
			{
				if(x!=v.parent)  Q.add(new Pair(x,v.second+1,v.first));
			}

		}

		return new Pair(choice,max);
	}

	public static void getDiameter(int idx)
	{

		Pair P  = bfs(idx,idx);
		P =	bfs(P.first,idx);
		D[idx] = (int)(P.second);

	}
	static int getLeader(int a)
	{
		if(leader[a] == a) return a;
		return leader[a] = getLeader(leader[a]);
	}
	static int merge(int u,int v)
	{
		int a = getLeader(u); int b = getLeader(v);
		D[b] = Math.max(Math.max(D[b],D[a]),((D[a]+1)/2)+((D[b]+1)/2)+1);

		leader[a] = b;
		return D[b];

	}

	static void set()
	{

		for(int i = 0; i < N ;i++)
		{
			if(!seen[i]) getDiameter(i);
		}

	}
	public static void main(String[]args)throws Throwable
	{

		st = new StringTokenizer(br.readLine());
		N = new Integer(st.nextToken());
		E = new Integer(st.nextToken());
		q = new Integer(st.nextToken());
		int u,v;
		DSU DSU = new DSU(N);
		for(int i = 0 ;i < N ;i++)tree[i] = new ArrayList();
		for(int i = 0 ; i < E ;i++)
		{
			st = new StringTokenizer(br.readLine());
			u = new Integer(st.nextToken())-1;
			v = new Integer(st.nextToken())-1;
			tree[u].add(v);
			tree[v].add(u);
			DSU.union(u,v);
		}
		set();
		int type;
		StringBuilder sb = new StringBuilder();
		for(int i = 0 ; i < q ;i++)
		{
			st = new StringTokenizer(br.readLine());
			type = new Integer(st.nextToken());
			if(type==2){
				u = new Integer(st.nextToken())-1;
				v = new Integer(st.nextToken())-1;
				u = getLeader(u);
				v = getLeader(v);
				if(!DSU.isSameSet(u, v))
				{
					DSU.union(u, v);
					merge(u,v);
				}
			}
			else
			{
				u = new Integer(st.nextToken())-1;
				sb.append(D[getLeader(u)]+"\n");
			}

		}
		System.out.println(sb);
	}
}


import java.util.*;
import java.io.*;
public class C455 {
public static void main(String[] args) throws IOException
{
    input.init(System.in);
    PrintWriter out = new PrintWriter(System.out);
    int n = input.nextInt(), m = input.nextInt(), Q = input.nextInt();
    int[] longest = new int[n];
    ArrayList<Integer>[] g = new ArrayList[n];
    for(int i = 0; i<n; i++) g[i] = new ArrayList<Integer>();
    DisjointSet ds = new DisjointSet(n);
    for(int i =0; i<m; i++)
    {
        int a = input.nextInt()-1, b = input.nextInt()-1;
        ds.union(a, b);
        g[a].add(b);
        g[b].add(a);
    }
    boolean[] vis = new boolean[n], vis2 = new boolean[n];
    int[] dist = new int[n];
    Queue<Integer> q = new LinkedList<Integer>();
    for(int i = 0; i<n; i++)
    {
        if(vis[i]) continue;
        ArrayList<Integer> comp = new ArrayList<Integer>();
        q.add(i);
        dist[i] = 0;
        vis[i] = true;
        while(!q.isEmpty())
        {
            int at = q.poll();
            comp.add(at);
            for(int e : g[at])
            {
                if(vis[e]) continue;
                q.add(e);
                vis[e] = true;
                dist[e] = 1 + dist[at];
            }
        }
        int last = comp.get(comp.size()-1);
        q.add(last);
        vis2[last] = true;
        dist[last] = 0;
        int max = 0;
        while(!q.isEmpty())
        {
            int at = q.poll();
            max = dist[at];
            for(int e : g[at])
            {
                if(vis2[e]) continue;
                vis2[e] = true;
                dist[e] = 1+dist[at];
                q.add(e);
            }
        }
        for(int x: comp) longest[x] = max;
    }
    ds.setSize(longest);
    for(int i = 0; i<Q; i++)
    {
        int type = input.nextInt();
        if(type == 1)
        {
            out.println(ds.size[ds.find(input.nextInt()-1)]);
        }
        else
        {
            ds.union(input.nextInt()-1, input.nextInt()-1);
        }
    }
    out.close();
}
public static class DisjointSet
{
    int[] map; //negative if root, more negative means bigger set; if nonnegative, then it indicates the parent
    int[] size;
    public DisjointSet(int n)
    {
        map = new int[n+1];
        Arrays.fill(map, -1);
        size = new int[n+1];
    }
    void setSize(int[] ss)
    {
        size = ss;
    }
    public int find(int x)
    {
        if(map[x] < 0)
            return x;
        else
        {
            map[x] = find(map[x]);
            return map[x];
        }
    }
    public void union(int a, int b)
    {
        int roota = find(a), rootb = find(b);
        if(roota == rootb)
            return;
        int nsize = Math.max(size[roota], Math.max(size[rootb], 1+(size[roota]+1)/2 + (size[rootb]+1)/2));
        size[roota] = size[rootb] = nsize;
        if(map[roota] < map[rootb])
        {
            map[roota] += map[rootb]; //add the sizes
            map[rootb] = roota; //connect the smaller to the bigger
        }
        else
        {
            map[rootb] += map[roota];
            map[roota] = rootb;
        }
    }
}
public static class input {
    static BufferedReader reader;
    static StringTokenizer tokenizer;

    /** call this method to initialize reader for InputStream */
    static void init(InputStream input) {
        reader = new BufferedReader(
                     new InputStreamReader(input) );
        tokenizer = new StringTokenizer("");
    }

    /** get next word */
    static String next() throws IOException {
        while ( ! tokenizer.hasMoreTokens() ) {
            //TODO add check for eof if necessary
            tokenizer = new StringTokenizer(
                   reader.readLine() );
        }
        return tokenizer.nextToken();
    }

    static int nextInt() throws IOException {
        return Integer.parseInt( next() );
    }

    static double nextDouble() throws IOException {
        return Double.parseDouble( next() );
    }
    static long nextLong() throws IOException {
        return Long.parseLong( next() );
    }
}
}


import java.io.*;
import java.util.*;

public class Civilization {
    // union find node
    Civilization parent = this;
    int rank = 0;
    int path = 0;
    Civilization find() {
        parent = parent==this? this : parent.find();
        return parent;
    }
    void union(Civilization o) {
        Civilization mRoot = find();
        Civilization oRoot = o.find();
        if (mRoot == oRoot) return;
        if (mRoot.rank < oRoot.rank) {
            mRoot.parent = oRoot;
            oRoot.path = mergePaths(mRoot.path, oRoot.path);
        } else {
            oRoot.parent = mRoot;
            mRoot.path = mergePaths(mRoot.path, oRoot.path);
            if (mRoot.rank == oRoot.rank) mRoot.rank++;
        }
    }
    int mergePaths(int a, int b) {
        return Math.max(Math.max(a,b), 1+(a+1)/2+(b+1)/2);
    }

    public static void main(String... args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String[] s = in.readLine().split(" ");
        int cities = Integer.parseInt(s[0]);
        int paths = Integer.parseInt(s[1]);
        int queries = Integer.parseInt(s[2]);
        @SuppressWarnings("unchecked")
        LinkedList<Integer>[] adjacency = new LinkedList[cities];
        for (int i=0;i<cities; i++) adjacency[i] = new LinkedList<Integer>();
        Civilization[] civ = new Civilization[cities];

        // read streets into adjacency
        for (int i=0; i<paths; i++) {
            s = in.readLine().split(" ");
            int a = Integer.parseInt(s[0])-1;
            int b = Integer.parseInt(s[1])-1;
            adjacency[a].add(b);
            adjacency[b].add(a);
        }

        // dfs to determine connected blocks and their maximum path length
        for (int i=0; i<cities; i++) {
            if (civ[i] != null) continue;
            Civilization curr = new Civilization();
            LinkedList<Integer> stack = new LinkedList<Integer>();

            int maxDist = 0;
            int maxCity = i;
            {
                stack.push(i);
                boolean[] expanded = new boolean[cities];
                int[]     dist     = new int[cities];
                while (!stack.isEmpty()) {
                    int n = stack.pop();
                    if (!expanded[n]) {
                        civ[n] = curr;
                        for (int c: adjacency[n]) {
                            if (!expanded[c]) {
                                stack.push(c);
                                dist[c] = dist[n] + 1;
                                if (dist[c]>maxDist) {
                                    maxDist = dist[c];
                                    maxCity = c;
                                }
                            }
                        }
                        expanded[n] = true;
                    }
                }
            }

            maxDist = 0;
            {
                stack.push(maxCity);
                boolean[] expanded = new boolean[cities];
                int[]     dist     = new int[cities];
                while (!stack.isEmpty()) {
                    int n = stack.pop();
                    if (!expanded[n]) {
                        for (int c: adjacency[n]) {
                            if (!expanded[c]) {
                                stack.push(c);
                                dist[c] = dist[n] + 1;
                                if (dist[c]>maxDist) {
                                    maxDist = dist[c];
                                }
                            }
                        }
                        expanded[n] = true;
                    }
                }
            }

            curr.path = maxDist;
        }

        // process queries
        StringBuilder sb = new StringBuilder();
        for (int i=0; i<queries; i++) {
            s = in.readLine().split(" ");
            if (Integer.parseInt(s[0])==1)
                sb.append(""+civ[Integer.parseInt(s[1])-1].find().path+"\n");
            else civ[Integer.parseInt(s[1])-1].union(civ[Integer.parseInt(s[2])-1]);
        }
        System.out.println(sb);
    }
}


import java.io.*;
import java.util.*;

public class Civilization {
    // union find node
    Civilization parent = this;
    int rank = 0;
    int path = 0;
    Civilization find() {
        parent = parent==this? this : parent.find();
        return parent;
    }
    void union(Civilization o) {
        Civilization mRoot = find();
        Civilization oRoot = o.find();
        if (mRoot == oRoot) return;
        if (mRoot.rank < oRoot.rank) {
            mRoot.parent = oRoot;
            oRoot.path = mergePaths(mRoot.path, oRoot.path);
        } else {
            oRoot.parent = mRoot;
            mRoot.path = mergePaths(mRoot.path, oRoot.path);
            if (mRoot.rank == oRoot.rank) mRoot.rank++;
        }
    }
    int mergePaths(int a, int b) {
        return Math.max(Math.max(a,b), 1+(a+1)/2+(b+1)/2);
    }

    public static void main(String... args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in), 1024*1024);
        String[] s = in.readLine().split(" ");
        int cities = Integer.parseInt(s[0]);
        int paths = Integer.parseInt(s[1]);
        int queries = Integer.parseInt(s[2]);
        @SuppressWarnings("unchecked")
        LinkedList<Integer>[] adjacency = new LinkedList[cities];
        for (int i=0;i<cities; i++) adjacency[i] = new LinkedList<Integer>();
        Civilization[] civ = new Civilization[cities];

        // read streets into adjacency
        for (int i=0; i<paths; i++) {
            s = in.readLine().split(" ");
            int a = Integer.parseInt(s[0])-1;
            int b = Integer.parseInt(s[1])-1;
            adjacency[a].add(b);
            adjacency[b].add(a);
        }

        // dfs to determine connected blocks and their maximum path length
        boolean[] expanded1 = new boolean[cities];
        int[]     dist1     = new int[cities];
        boolean[] expanded2 = new boolean[cities];
        int[]     dist2     = new int[cities];
        for (int i=0; i<cities; i++) {
            if (civ[i] != null) continue;
            Civilization curr = new Civilization();
            LinkedList<Integer> stack = new LinkedList<Integer>();

            int maxDist = 0;
            int maxCity = i;
            {
                stack.push(i);
                while (!stack.isEmpty()) {
                    int n = stack.pop();
                    if (!expanded1[n]) {
                        civ[n] = curr;
                        for (int c: adjacency[n]) {
                            if (!expanded1[c]) {
                                stack.push(c);
                                dist1[c] = dist1[n] + 1;
                                if (dist1[c]>maxDist) {
                                    maxDist = dist1[c];
                                    maxCity = c;
                                }
                            }
                        }
                        expanded1[n] = true;
                    }
                }
            }

            maxDist = 0;
            {
                stack.push(maxCity);
                while (!stack.isEmpty()) {
                    int n = stack.pop();
                    if (!expanded2[n]) {
                        for (int c: adjacency[n]) {
                            if (!expanded2[c]) {
                                stack.push(c);
                                dist2[c] = dist2[n] + 1;
                                if (dist2[c]>maxDist) {
                                    maxDist = dist2[c];
                                }
                            }
                        }
                        expanded2[n] = true;
                    }
                }
            }

            curr.path = maxDist;
        }

        // process queries
        StringBuilder sb = new StringBuilder();
        for (int i=0; i<queries; i++) {
            s = in.readLine().split(" ");
            if (Integer.parseInt(s[0])==1)
                sb.append(""+civ[Integer.parseInt(s[1])-1].find().path+"\n");
            else civ[Integer.parseInt(s[1])-1].union(civ[Integer.parseInt(s[2])-1]);
        }
        System.out.println(sb);
    }
}


import java.io.*;
import java.util.*;

public class Civilization {
    // union find node
    Civilization parent = this;
    int rank = 0;
    int path = 0;
    Civilization find() {
        parent = parent==this? this : parent.find();
        return parent;
    }
    void union(Civilization o) {
        Civilization mRoot = find();
        Civilization oRoot = o.find();
        if (mRoot == oRoot) return;
        if (mRoot.rank < oRoot.rank) {
            mRoot.parent = oRoot;
            oRoot.path = mergePaths(mRoot.path, oRoot.path);
        } else {
            oRoot.parent = mRoot;
            mRoot.path = mergePaths(mRoot.path, oRoot.path);
            if (mRoot.rank == oRoot.rank) mRoot.rank++;
        }
    }
    int mergePaths(int a, int b) {
        return Math.max(Math.max(a,b), 1+(a+1)/2+(b+1)/2);
    }

    public static void main(String... args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String[] s = in.readLine().split(" ");
        int cities = Integer.parseInt(s[0]);
        int paths = Integer.parseInt(s[1]);
        int queries = Integer.parseInt(s[2]);
        Vector<Integer>[] adjacency = new Vector[cities];
        for (int i=0;i<cities; i++) adjacency[i] = new Vector<Integer>();
        Civilization[] civ = new Civilization[cities];

        // read streets into adjacency
        for (int i=0; i<paths; i++) {
            s = in.readLine().split(" ");
            int a = Integer.parseInt(s[0])-1;
            int b = Integer.parseInt(s[1])-1;
            adjacency[a].add(b);
            adjacency[b].add(a);
        }

        // dfs to determine connected blocks and their maximum path length
        for (int i=0; i<cities; i++) {
            if (civ[i] != null) continue;
            Civilization curr = new Civilization();
            LinkedList<Integer> stack = new LinkedList<Integer>();

            int maxDist = 0;
            int maxCity = i;
            {
                stack.add(i);
                boolean[] expanded = new boolean[cities];
                int[]     dist     = new int[cities];
                while (!stack.isEmpty()) {
                    int n = stack.pop();
                    if (!expanded[n]) {
                        civ[n] = curr;
                        for (int c: adjacency[n]) {
                            if (!expanded[c]) {
                                stack.add(0, c);
                                dist[c] = dist[n] + 1;
                                if (dist[c]>maxDist) {
                                    maxDist = dist[c];
                                    maxCity = c;
                                }
                            }
                        }
                        expanded[n] = true;
                    }
                }
            }

            maxDist = 0;
            {
                stack.add(maxCity);
                boolean[] expanded = new boolean[cities];
                int[]     dist     = new int[cities];
                while (!stack.isEmpty()) {
                    int n = stack.pop();
                    if (!expanded[n]) {
                        for (int c: adjacency[n]) {
                            if (!expanded[c]) {
                                stack.add(0, c);
                                dist[c] = dist[n] + 1;
                                if (dist[c]>maxDist) {
                                    maxDist = dist[c];
                                }
                            }
                        }
                        expanded[n] = true;
                    }
                }
            }

            curr.path = maxDist;
        }

        // process queries
        for (int i=0; i<queries; i++) {
            s = in.readLine().split(" ");
            if (Integer.parseInt(s[0])==1)
                System.out.println(civ[Integer.parseInt(s[1])-1].find().path);
            else civ[Integer.parseInt(s[1])-1].union(civ[Integer.parseInt(s[2])-1]);
        }
    }
}


import java.io.*;
import java.util.*;

public class Civilization {
    // union find node
    Civilization parent = this;
    int rank = 0;
    int path = 0;
    Civilization find() {
        parent = parent==this? this : parent.find();
        return parent;
    }
    void union(Civilization o) {
        Civilization mRoot = find();
        Civilization oRoot = o.find();
        if (mRoot == oRoot) return;
        if (mRoot.rank < oRoot.rank) {
            mRoot.parent = oRoot;
            oRoot.path = mergePaths(mRoot.path, oRoot.path);
        } else {
            oRoot.parent = mRoot;
            mRoot.path = mergePaths(mRoot.path, oRoot.path);
            if (mRoot.rank == oRoot.rank) mRoot.rank++;
        }
    }
    int mergePaths(int a, int b) {
        return Math.max(Math.max(a,b), 1+(a+1)/2+(b+1)/2);
    }

    public static void main(String... args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String[] s = in.readLine().split(" ");
        int cities = Integer.parseInt(s[0]);
        int paths = Integer.parseInt(s[1]);
        int queries = Integer.parseInt(s[2]);
        Vector<Integer>[] adjacency = new Vector[cities];
        for (int i=0;i<cities; i++) adjacency[i] = new Vector<Integer>();
        Civilization[] civ = new Civilization[cities];

        // read streets into adjacency
        for (int i=0; i<paths; i++) {
            s = in.readLine().split(" ");
            int a = Integer.parseInt(s[0])-1;
            int b = Integer.parseInt(s[1])-1;
            adjacency[a].add(b);
            adjacency[b].add(a);
        }

        // dfs to determine connected blocks and their maximum path length
        for (int i=0; i<cities; i++) {
            if (civ[i] != null) continue;
            Civilization curr = new Civilization();
            LinkedList<Integer> stack = new LinkedList<Integer>();

            int maxDist = 0;
            int maxCity = 0;
            {
                stack.add(i);
                boolean[] expanded = new boolean[cities];
                int[]     dist     = new int[cities];
                while (!stack.isEmpty()) {
                    int n = stack.pop();
                    if (!expanded[n]) {
                        civ[n] = curr;
                        for (int c: adjacency[n]) {
                            if (!expanded[c]) {
                                stack.add(c);
                                dist[c] = dist[n] + 1;
                                if (dist[c]>maxDist) {
                                    maxDist = dist[c];
                                    maxCity = c;
                                }
                            }
                        }
                        expanded[n] = true;
                    }
                }
            }

            maxDist = 0;
            {
                stack.add(maxCity);
                boolean[] expanded = new boolean[cities];
                int[]     dist     = new int[cities];
                while (!stack.isEmpty()) {
                    int n = stack.pop();
                    if (!expanded[n]) {
                        for (int c: adjacency[n]) {
                            if (!expanded[c]) {
                                stack.add(c);
                                dist[c] = dist[n] + 1;
                                if (dist[c]>maxDist) {
                                    maxDist = dist[c];
                                }
                            }
                        }
                        expanded[n] = true;
                    }
                }
            }

            curr.path = maxDist;
        }

        // process queries
        for (int i=0; i<queries; i++) {
            s = in.readLine().split(" ");
            if (Integer.parseInt(s[0])==1)
                System.out.println(civ[Integer.parseInt(s[1])-1].find().path);
            else civ[Integer.parseInt(s[1])-1].union(civ[Integer.parseInt(s[2])-1]);
        }
    }
}


import java.io.*;
import java.util.*;

public class Civilization {
    // union find node
    Civilization parent = this;
    int rank = 0;
    int path = 0;
    Civilization find() {
        parent = parent==this? this : parent.find();
        return parent;
    }
    void union(Civilization o) {
        Civilization mRoot = find();
        Civilization oRoot = o.find();
        if (mRoot == oRoot) return;
        if (mRoot.rank < oRoot.rank) {
            mRoot.parent = oRoot;
            oRoot.path = mergePaths(mRoot.path, oRoot.path);
        } else {
            oRoot.parent = mRoot;
            mRoot.path = mergePaths(mRoot.path, oRoot.path);
            if (mRoot.rank == oRoot.rank) mRoot.rank++;
        }
    }
    int mergePaths(int a, int b) {
        return Math.max(Math.max(a,b), 1+(a+1)/2+(b+1)/2);
    }

    public static void main(String... args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String[] s = in.readLine().split(" ");
        int cities = Integer.parseInt(s[0]);
        int paths = Integer.parseInt(s[1]);
        int queries = Integer.parseInt(s[2]);
        Vector<Integer>[] adjacency = new Vector[cities];
        for (int i=0;i<cities; i++) adjacency[i] = new Vector<Integer>();
        Civilization[] civ = new Civilization[cities];

        // read streets into adjacency
        for (int i=0; i<paths; i++) {
            s = in.readLine().split(" ");
            int a = Integer.parseInt(s[0])-1;
            int b = Integer.parseInt(s[1])-1;
            adjacency[a].add(b);
            adjacency[b].add(a);
        }

        // dfs to determine connected blocks and their maximum path length
        for (int i=0; i<cities; i++) {
            if (civ[i] != null) continue;
            Civilization curr = new Civilization();
            LinkedList<Integer> stack = new LinkedList<Integer>();

            int maxDist = 0;
            int maxCity = i;
            {
                stack.push(i);
                boolean[] expanded = new boolean[cities];
                int[]     dist     = new int[cities];
                while (!stack.isEmpty()) {
                    int n = stack.pop();
                    if (!expanded[n]) {
                        civ[n] = curr;
                        for (int c: adjacency[n]) {
                            if (!expanded[c]) {
                                stack.push(c);
                                dist[c] = dist[n] + 1;
                                if (dist[c]>maxDist) {
                                    maxDist = dist[c];
                                    maxCity = c;
                                }
                            }
                        }
                        expanded[n] = true;
                    }
                }
            }

            maxDist = 0;
            {
                stack.push(maxCity);
                boolean[] expanded = new boolean[cities];
                int[]     dist     = new int[cities];
                while (!stack.isEmpty()) {
                    int n = stack.pop();
                    if (!expanded[n]) {
                        for (int c: adjacency[n]) {
                            if (!expanded[c]) {
                                stack.push(c);
                                dist[c] = dist[n] + 1;
                                if (dist[c]>maxDist) {
                                    maxDist = dist[c];
                                }
                            }
                        }
                        expanded[n] = true;
                    }
                }
            }

            curr.path = maxDist;
        }

        // process queries
        for (int i=0; i<queries; i++) {
            s = in.readLine().split(" ");
            if (Integer.parseInt(s[0])==1)
                System.out.println(civ[Integer.parseInt(s[1])-1].find().path);
            else civ[Integer.parseInt(s[1])-1].union(civ[Integer.parseInt(s[2])-1]);
        }
    }
}


import java.io.*;
import java.util.*;

public class Civ {
    static int findSet(int i, int[] sets) {
        if (sets[i]==0) return i;
        return sets[i] = findSet(sets[i], sets);
    }

    static void mergeSets(int i, int j, int[] sets, int[] rank, int[] path) {
        i = findSet(i, sets);
        j = findSet(j, sets);
        if (i==j) return;
        if (rank[i]<rank[j]) {int tmp=i; i=j; j=tmp;}
        sets[j] = i;
        if (rank[i]==rank[j]) rank[i]++;
        path[i] = Math.max(Math.max(path[i], path[j]), 1+(path[i]+1)/2+(path[j]+1)/2);
    }

    static int dfs(int start, LinkedList<Integer>[] adj, boolean[] explored, int[] dist,
             int[] sets, int[] rank, int[] path, boolean getCity) {
        int maxCity = start;
        int maxDist = dist[maxCity];
        LinkedList<Integer> stack = new LinkedList<Integer>();
        stack.push(start);
        explored[start] = true;
        while (!stack.isEmpty()) {
            int n = stack.pop();
            for (int c: adj[n]) {
                if (explored[c]) continue;
                stack.push(c);
                mergeSets(n, c, sets, rank, path);
                dist[c] = dist[n] + 1;
                if (dist[c]>maxDist) {
                    maxDist = dist[c];
                    maxCity = c;
                }
                explored[c] = true;
            }
        }
        return getCity? maxCity: maxDist;
    }

    public static void main(String... args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in), 128*1024);
        String[] s = in.readLine().split(" ");
        int cities = Integer.parseInt(s[0]);
        int edges = Integer.parseInt(s[1]);
        int queries = Integer.parseInt(s[2]);
        @SuppressWarnings("unchecked")
        LinkedList<Integer>[] adj = new LinkedList[cities+1];
        for (int i=1; i<=cities; i++) adj[i] = new LinkedList<Integer>();
        int[] sets = new int[cities+1];
        int[] rank = new int[cities+1];
        int[] path = new int[cities+1];

        // read edges into adjacency list
        for (int i=1; i<=edges; i++) {
            s = in.readLine().split(" ");
            int a = Integer.parseInt(s[0]);
            int b = Integer.parseInt(s[1]);
            adj[a].add(b); adj[b].add(a);
        }

        // DFS to determine connected blocks and their maximum path length
        boolean[] explored1 = new boolean[cities+1];
        boolean[] explored2 = new boolean[cities+1];
        int[]     dist1     = new int[cities+1];
        int[]     dist2     = new int[cities+1];

        for (int i=1; i<=cities; i++) {
            if (explored1[i]) continue;
            int c = dfs(i, adj, explored1, dist1, sets, rank, path, true);
            int l = dfs(c, adj, explored2, dist2, sets, rank, path, false);
            path[findSet(i, sets)] = l;
        }

        // process queries
        StringBuilder sb = new StringBuilder();
        for (int i=1; i<=queries; i++) {
            s = in.readLine().split(" ");
            if (Integer.parseInt(s[0])==1) sb.append(""+path[findSet(Integer.parseInt(s[1]), sets)]+"\n");
            else mergeSets(Integer.parseInt(s[1]), Integer.parseInt(s[2]), sets, rank, path);
        }
        System.out.println(sb);
    }
}


import java.io.*;
import java.util.*;

public class Civilization {
    // union find node
    Civilization parent = this;
    int rank = 0;
    int path = 0;
    Civilization find() {
        parent = parent==this? this : parent.find();
        return parent;
    }
    void union(Civilization o) {
        Civilization mRoot = find();
        Civilization oRoot = o.find();
        if (mRoot == oRoot) return;
        if (mRoot.rank < oRoot.rank) {
            mRoot.parent = oRoot;
            oRoot.path = mergePaths(mRoot.path, oRoot.path);
        } else {
            oRoot.parent = mRoot;
            mRoot.path = mergePaths(mRoot.path, oRoot.path);
            if (mRoot.rank == oRoot.rank) mRoot.rank++;
        }
    }
    int mergePaths(int a, int b) {
        return Math.max(Math.max(a,b), 1+(a+1)/2+(b+1)/2);
    }

    public static void main(String... args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String[] s = in.readLine().split(" ");
        int cities = Integer.parseInt(s[0]);
        int paths = Integer.parseInt(s[1]);
        int queries = Integer.parseInt(s[2]);
        @SuppressWarnings("unchecked")
        LinkedList<Integer>[] adjacency = new LinkedList[cities];
        for (int i=0;i<cities; i++) adjacency[i] = new LinkedList<Integer>();
        Civilization[] civ = new Civilization[cities];

        // read streets into adjacency
        for (int i=0; i<paths; i++) {
            s = in.readLine().split(" ");
            int a = Integer.parseInt(s[0])-1;
            int b = Integer.parseInt(s[1])-1;
            adjacency[a].add(b);
            adjacency[b].add(a);
        }

        // dfs to determine connected blocks and their maximum path length
        boolean[] expanded1 = new boolean[cities];
        int[]     dist1     = new int[cities];
        boolean[] expanded2 = new boolean[cities];
        int[]     dist2     = new int[cities];
        for (int i=0; i<cities; i++) {
            if (civ[i] != null) continue;
            Civilization curr = new Civilization();
            LinkedList<Integer> stack = new LinkedList<Integer>();

            int maxDist = 0;
            int maxCity = i;
            {
                stack.push(i);
                while (!stack.isEmpty()) {
                    int n = stack.pop();
                    if (!expanded1[n]) {
                        civ[n] = curr;
                        for (int c: adjacency[n]) {
                            if (!expanded1[c]) {
                                stack.push(c);
                                dist1[c] = dist1[n] + 1;
                                if (dist1[c]>maxDist) {
                                    maxDist = dist1[c];
                                    maxCity = c;
                                }
                            }
                        }
                        expanded1[n] = true;
                    }
                }
            }

            maxDist = 0;
            {
                stack.push(maxCity);
                while (!stack.isEmpty()) {
                    int n = stack.pop();
                    if (!expanded2[n]) {
                        for (int c: adjacency[n]) {
                            if (!expanded2[c]) {
                                stack.push(c);
                                dist2[c] = dist2[n] + 1;
                                if (dist2[c]>maxDist) {
                                    maxDist = dist2[c];
                                }
                            }
                        }
                        expanded2[n] = true;
                    }
                }
            }

            curr.path = maxDist;
        }

        // process queries
        StringBuilder sb = new StringBuilder();
        for (int i=0; i<queries; i++) {
            s = in.readLine().split(" ");
            if (Integer.parseInt(s[0])==1)
                sb.append(""+civ[Integer.parseInt(s[1])-1].find().path+"\n");
            else civ[Integer.parseInt(s[1])-1].union(civ[Integer.parseInt(s[2])-1]);
        }
        System.out.println(sb);
    }
}


import java.io.*;
import java.util.*;

public class Civ {
    static int findSet(int i, int[] sets) {
        if (sets[i]==0) return i;
        return sets[i] = findSet(sets[i], sets);
    }

    static void mergeSets(int i, int j, int[] sets, int[] rank, int[] plen) {
        i = findSet(i, sets);
        j = findSet(j, sets);
        if (i==j) return;
        if (rank[i]<rank[j]) {int tmp=i; i=j; j=tmp;}
        sets[j] = i;
        if (rank[i]==rank[j]) rank[i]++;
        plen[i] = Math.max(Math.max(plen[i], plen[j]), 1+(plen[i]+1)/2+(plen[j]+1)/2);
    }

    static int dfs(int start, LinkedList<Integer>[] adj, boolean[] explored, int[] dist,
             int[] sets, int[] rank, int[] plen, boolean getCity) {
        int maxCity = start;
        int maxDist = dist[maxCity];
        LinkedList<Integer> stack = new LinkedList<Integer>();
        stack.push(start);
        while (!stack.isEmpty()) {
            int n = stack.pop();
            if (!explored[n]) {
                for (int c: adj[n]) {
                    stack.push(c);
                    mergeSets(n, c, sets, rank, plen);
                    dist[c] = dist[n] + 1;
                    if (dist[c]>maxDist) {
                        maxDist = dist[c];
                        maxCity = c;
                    }
                }
                explored[n] = true;
            }
        }
        return getCity? maxCity: maxDist;
    }

    public static void main(String... args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in), 128*1024);
        String[] s = in.readLine().split(" ");
        int cities = Integer.parseInt(s[0]);
        int paths = Integer.parseInt(s[1]);
        int queries = Integer.parseInt(s[2]);
        @SuppressWarnings("unchecked")
        LinkedList<Integer>[] adj = new LinkedList[cities+1];
        for (int i=1; i<=cities; i++) adj[i] = new LinkedList<Integer>();
        int[] sets = new int[cities+1];
        int[] rank = new int[cities+1];
        int[] plen = new int[cities+1];

        // read streets into adjacency list
        for (int i=1; i<=paths; i++) {
            s = in.readLine().split(" ");
            int a = Integer.parseInt(s[0]);
            int b = Integer.parseInt(s[1]);
            adj[a].add(b); adj[b].add(a);
        }

        // DFS to determine connected blocks and their maximum path length
        boolean[] explored1 = new boolean[cities+1];
        boolean[] explored2 = new boolean[cities+1];
        int[]     dist1     = new int[cities+1];
        int[]     dist2     = new int[cities+1];

        for (int i=1; i<=cities; i++) {
            if (explored1[i]) continue;
            int c = dfs(i, adj, explored1, dist1, sets, rank, plen, true);
            int l = dfs(c, adj, explored2, dist2, sets, rank, plen, false);
            plen[findSet(i, sets)] = l;
        }

        // process queries
        StringBuilder sb = new StringBuilder();
        for (int i=1; i<=queries; i++) {
            s = in.readLine().split(" ");
            if (Integer.parseInt(s[0])==1) sb.append(""+plen[findSet(Integer.parseInt(s[1]), sets)]+"\n");
            else mergeSets(Integer.parseInt(s[1]), Integer.parseInt(s[2]), sets, rank, plen);
        }
        System.out.println(sb);
    }
}


import java.io.*;
import java.util.*;

public class Civilization {
    // union find node
    Civilization parent = this;
    int rank = 0;
    int path = 0;
    Civilization find() {
        parent = parent==this? this : parent.find();
        return parent;
    }
    void union(Civilization o) {
        Civilization mRoot = find();
        Civilization oRoot = o.find();
        if (mRoot == oRoot) return;
        if (mRoot.rank < oRoot.rank) {
            mRoot.parent = oRoot;
            oRoot.path = mergePaths(mRoot.path, oRoot.path);
        } else {
            oRoot.parent = mRoot;
            mRoot.path = mergePaths(mRoot.path, oRoot.path);
            if (mRoot.rank == oRoot.rank) mRoot.rank++;
        }
    }
    int mergePaths(int a, int b) {
        return Math.max(Math.max(a,b), 1+(a+1)/2+(b+1)/2);
    }

    public static void main(String... args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String[] s = in.readLine().split(" ");
        int cities = Integer.parseInt(s[0]);
        int paths = Integer.parseInt(s[1]);
        int queries = Integer.parseInt(s[2]);
        Vector<Integer>[] adjacency = new Vector[cities];
        for (int i=0;i<cities; i++) adjacency[i] = new Vector<Integer>();
        Civilization[] civ = new Civilization[cities];

        // read streets into adjacency
        for (int i=0; i<paths; i++) {
            s = in.readLine().split(" ");
            int a = Integer.parseInt(s[0])-1;
            int b = Integer.parseInt(s[1])-1;
            adjacency[a].add(b);
            adjacency[b].add(a);
        }

        // dfs to determine connected blocks and their maximum path length
        for (int i=0; i<cities; i++) {
            if (civ[i] != null) continue;
            Civilization curr = new Civilization();
            LinkedList<Integer> stack = new LinkedList<Integer>();

            int maxDist = 0;
            int maxCity = i;
            {
                stack.push(i);
                boolean[] expanded = new boolean[cities];
                int[]     dist     = new int[cities];
                while (!stack.isEmpty()) {
                    int n = stack.pop();
                    if (!expanded[n]) {
                        civ[n] = curr;
                        for (int c: adjacency[n]) {
                            if (!expanded[c]) {
                                stack.push(c);
                                dist[c] = dist[n] + 1;
                                if (dist[c]>maxDist) {
                                    maxDist = dist[c];
                                    maxCity = c;
                                }
                            }
                        }
                        expanded[n] = true;
                    }
                }
            }

            maxDist = 0;
            {
                stack.push(maxCity);
                boolean[] expanded = new boolean[cities];
                int[]     dist     = new int[cities];
                while (!stack.isEmpty()) {
                    int n = stack.pop();
                    if (!expanded[n]) {
                        for (int c: adjacency[n]) {
                            if (!expanded[c]) {
                                stack.push(c);
                                dist[c] = dist[n] + 1;
                                if (dist[c]>maxDist) {
                                    maxDist = dist[c];
                                }
                            }
                        }
                        expanded[n] = true;
                    }
                }
            }

            curr.path = maxDist;
        }

        // process queries
        StringBuilder sb = new StringBuilder();
        for (int i=0; i<queries; i++) {
            s = in.readLine().split(" ");
            if (Integer.parseInt(s[0])==1)
                sb.append(""+civ[Integer.parseInt(s[1])-1].find().path+"\n");
            else civ[Integer.parseInt(s[1])-1].union(civ[Integer.parseInt(s[2])-1]);
        }
        System.out.println(sb);
    }
}


import java.io.*;
import java.math.*;
import java.util.*;

public class Main{
    FastScanner in;
    PrintWriter out;

    ArrayList< ArrayList<Integer> > list;
    int dist, fnd;

    public static class DSU {

        public static Random rnd;
        public static int[] par;
        public static int[] diam;

        public DSU(int n) {
            rnd = new Random();
            par = new int[n+1];
            diam = new int[n+1];
            for (int i = 1; i <= n; i++) {
                par[i] = i;
                diam[i] = 0;
            }
        }

        public static int get_set(int v) {
            if (v == par[v])
                return v;
            return par[v] = get_set(par[v]);
        }

        public static void union_sets(int a, int b) {
            a = get_set(a);
            b = get_set(b);
            if (a == b)
                return;

            if (rnd.nextBoolean()) {
                int tmp = a;
                a = b;
                b = tmp;
            }

            diam[b] = Math.max(diam[b], Math.max(diam[a], (int)((diam[a]+1)/2) + (int)((diam[b]+1)/2) + 1));

            par[a] = b;
        }

        public static void setDiam(int[] diam1) {
            for (int i = 0; i < diam1.length; i++)
                diam[i] = diam1[i];
        }

        public static int getDiam(int a) {
            return diam[get_set(a)];
        }
    }

    public int dfs(int v, int from) {
        int mx = -1;
        for (int to : list.get(v))
        if (to != from)
            mx = Math.max(mx, dfs(to, v));
        return mx+1;
    }

    public void find(int v, int dst, int from) {
        if (dist < dst) {
            dist = dst;
            fnd = v;
        }

        for (int to : list.get(v))
        if (to != from)
            find(to, dst+1,  v);
    }

    public void solve()
    {
        int n = in.nextInt();
        int m = in.nextInt();
        int k = in.nextInt();

        DSU dsu = new DSU(n);

        list = new ArrayList<>();
        for (int i = 0; i < n+1; i++) {
            list.add(new ArrayList<Integer>());
        }

        int a, b, t;
        for (int i = 0; i < m; i++) {
            a = in.nextInt();
            b = in.nextInt();

            list.get(a).add(b);
            list.get(b).add(a);

            dsu.union_sets(a, b);
        }

        int[] diam = new int [n+1];
        for (int i = 1; i <= n; i++)
        if(dsu.get_set(i) == i) {

            dist = -1;
            find(i, 0, -1);
            diam[i] = dfs(fnd, -1);

            //out.println(i + " " + diam[i]);
        }

        dsu.setDiam(diam);

        for (int i = 0; i < k; i++) {
            t = in.nextInt();
            if (t == 1) {
                out.println(dsu.getDiam(in.nextInt()));
            }
            else {
                dsu.union_sets(in.nextInt(), in.nextInt());
            }
        }
    }

    public void run()
    {
        in = new FastScanner();
        out = new PrintWriter(System.out);

        solve();

        out.close();
    }

    public static void main(String[] args) {
        new Main().run();
    }

    class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        FastScanner() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }
    }
}


import java.io.*;
import java.math.*;
import java.util.*;

public class Main{
    FastScanner in;
    PrintWriter out;

    ArrayList< ArrayList<Integer> > list;

    public static class DSU {

        public static Random rnd;
        public static int[] par;
        public static int[] diam;

        public DSU(int n) {
            rnd = new Random();
            par = new int[n+1];
            diam = new int[n+1];
            for (int i = 1; i <= n; i++) {
                par[i] = i;
                diam[i] = 0;
            }
        }

        public static int get_set(int v) {
            if (v == par[v])
                return v;
            return par[v] = get_set(par[v]);
        }

        public static void union_sets(int a, int b) {
            a = get_set(a);
            b = get_set(b);
            if (a == b)
                return;

            if (rnd.nextBoolean()) {
                int tmp = a;
                a = b;
                b = tmp;
            }

            diam[b] = Math.max(diam[b], Math.max(diam[a], (int)((diam[a]+1)/2) + (int)((diam[b]+1)/2) + 1));

            par[a] = b;
        }

        public static void setDiam(int[] diam1) {
            for (int i = 0; i < diam1.length; i++)
                diam[i] = diam1[i];
        }

        public static int getDiam(int a) {
            return diam[get_set(a)];
        }
    }

    public int dfs(int v, int from) {
        int mx = 0;
        for (int to : list.get(v))
        if (to != from)
            mx = Math.max(mx, dfs(to, v)+1);
        return mx;
    }

    public void solve()
    {
        int n = in.nextInt();
        int m = in.nextInt();
        int k = in.nextInt();

        DSU dsu = new DSU(n);

        list = new ArrayList<>();
        for (int i = 0; i < n+1; i++) {
            list.add(new ArrayList<Integer>());
        }

        int a, b, t;
        for (int i = 0; i < m; i++) {
            a = in.nextInt();
            b = in.nextInt();

            list.get(a).add(b);
            list.get(b).add(a);

            dsu.union_sets(a, b);
        }

        int[] diam = new int [n+1];
        for (int i = 1; i <= n; i++)
        if(dsu.get_set(i) == i) {

            ArrayList<Integer> l = new ArrayList<>();
            for (int to : list.get(i)) {
                l.add(dfs(to, i)+1);
            }

            Collections.sort(l);
            if (l.size() == 0)
                diam[i] = 0;
            else if (l.size() == 1)
                diam[i] = l.get(0);
            else
                diam[i] = l.get(l.size()-1) + l.get(l.size()-2);

            //out.println(i + " " + diam[i]);
        }

        dsu.setDiam(diam);

        for (int i = 0; i < k; i++) {
            t = in.nextInt();
            if (t == 1) {
                out.println(dsu.getDiam(in.nextInt()));
            }
            else {
                dsu.union_sets(in.nextInt(), in.nextInt());
            }
        }
    }

    public void run()
    {
        in = new FastScanner();
        out = new PrintWriter(System.out);

        solve();

        out.close();
    }

    public static void main(String[] args) {
        new Main().run();
    }

    class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        FastScanner() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }
    }
}


import java.io.*;
import java.math.*;
import java.util.*;

public class Main{
    FastScanner in;
    PrintWriter out;

    public static class DSU {

        public static Random rnd = new Random();

        public static int get_set(int v, int[] par) {
            if (v == par[v])
                return v;
            return par[v] = get_set(par[v], par);
        }

        public static void union_sets(int a, int b, int[] par, int[] diam) {
            a = get_set(a, par);
            b = get_set(b, par);
            if (a == b)
                return;

            if (rnd.nextBoolean()) {
                int tmp = a;
                a = b;
                b = tmp;
            }

            if (diam[b] < (diam[a]+1)/2+(diam[b]+1)/2+1)
                diam[b] = (diam[a]+1)/2+(diam[b]+1)/2+1;
            if (diam[b] < diam[a])
                diam[b] = diam[a];
            par[a] = b;
        }
    }

    public void solve()
    {
        int n = in.nextInt();
        int m = in.nextInt();
        int k = in.nextInt();

        int[] par = new int[n+1];
        int[] diam = new int[n+1];

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

        DSU dsu = new DSU();

        int a, b, t;
        for (int i = 0; i < m; i++) {
            a = in.nextInt();
            b = in.nextInt();

            if (par[a] != par[b])
                dsu.union_sets(a, b, par, diam);
        }

        for (int i = 0; i < k; i++) {
            t = in.nextInt();
            if (t == 1) {
                out.println(diam[dsu.get_set(in.nextInt(), par)]);
            }
            else {
                dsu.union_sets(in.nextInt(), in.nextInt(), par, diam);
            }
        }
    }

    public void run()
    {
        in = new FastScanner();
        out = new PrintWriter(System.out);

        solve();

        out.close();
    }

    public static void main(String[] args) {
        new Main().run();
    }

    class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        FastScanner() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }
    }
}


import java.io.*;
import java.math.*;
import java.util.*;

public class Main{
    FastScanner in;
    PrintWriter out;

    ArrayList< ArrayList<Integer> > list;
    int dist, fnd;

    public static class DSU {

        public static Random rnd;
        public static int[] par;
        public static int[] diam;

        public DSU(int n) {
            rnd = new Random();
            par = new int[n+1];
            diam = new int[n+1];
            for (int i = 1; i <= n; i++) {
                par[i] = i;
                diam[i] = 0;
            }
        }

        public static int get_set(int v) {
            if (v == par[v])
                return v;
            return get_set(par[v]);
        }

        public static void union_sets(int a, int b) {
            a = get_set(a);
            b = get_set(b);
            if (a == b)
                return;

            if (rnd.nextBoolean()) {
                int tmp = a;
                a = b;
                b = tmp;
            }

            diam[b] = Math.max(diam[b], Math.max(diam[a], (int)((diam[a]+1)/2) + (int)((diam[b]+1)/2) + 1));

            par[a] = b;
        }

        public static void setDiam(int[] diam1) {
            for (int i = 0; i < diam1.length; i++)
                diam[i] = diam1[i];
        }

        public static int getDiam(int a) {
            return diam[get_set(a)];
        }
    }

    public int dfs(int v, int from) {
        int mx = -1;
        for (int to : list.get(v))
        if (to != from)
            mx = Math.max(mx, dfs(to, v));
        return mx+1;
    }

    public void find(int v, int dst, int from) {
        if (dist < dst) {
            dist = dst;
            fnd = v;
        }

        for (int to : list.get(v))
        if (to != from)
            find(to, dst+1,  v);
    }

    public void solve()
    {
        int n = in.nextInt();
        int m = in.nextInt();
        int k = in.nextInt();

        DSU dsu = new DSU(n);

        list = new ArrayList<>();
        for (int i = 0; i < n+1; i++) {
            list.add(new ArrayList<Integer>());
        }

        int a, b, t;
        for (int i = 0; i < m; i++) {
            a = in.nextInt();
            b = in.nextInt();

            list.get(a).add(b);
            list.get(b).add(a);

            dsu.union_sets(a, b);
        }

        int[] diam = new int [n+1];
        for (int i = 1; i <= n; i++)
        if(dsu.get_set(i) == i) {

            dist = -1;
            find(i, 0, -1);
            diam[i] = dfs(fnd, -1);

            //out.println(i + " " + diam[i]);
        }

        dsu.setDiam(diam);

        for (int i = 0; i < k; i++) {
            t = in.nextInt();
            if (t == 1) {
                out.println(dsu.getDiam(in.nextInt()));
            }
            else {
                dsu.union_sets(in.nextInt(), in.nextInt());
            }
        }
    }

    public void run()
    {
        in = new FastScanner();
        out = new PrintWriter(System.out);

        solve();

        out.close();
    }

    public static void main(String[] args) {
        new Main().run();
    }

    class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        FastScanner() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }
    }
}


import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.InputMismatchException;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Random;
import java.util.Set;
import java.util.SortedSet;
import java.util.Stack;
import java.util.TreeMap;
import java.util.TreeSet;

public class Main
{
	private ArrayList<Integer>[] edge;
	private int[] father;
	private int root;
	private int end;
	private int diameter;
	private int[] d;

	public void dfs(int u, int pre, int s)
	{
		father[u] = root;
		if(s > diameter)
		{
			diameter = s;
			end = u;
		}
		for(int v: edge[u])
		{
			if(v != pre)
			{
				dfs(v, u, s + 1);
			}
		}
	}

	public int findFather(int x)
	{
		return x == father[x] ? x : (father[x] = findFather(father[x]));
	}

	public void unionSet(int x, int y)
	{
		x = findFather(x);
		y = findFather(y);
		if(x == y)
		{
			return;
		}
		father[y] = x;
		if(d[x] < d[y])
		{
			int tmp = d[x];
			d[x] = d[y];
			d[y] = tmp;
		}
		d[x] = Math.max(d[x], (d[x] + 1) / 2 + (d[y] + 1) / 2 + 1);
	}

	public void foo()
	{
		MyScanner scan = new MyScanner();
		int n = scan.nextInt();
		int m = scan.nextInt();
		int q = scan.nextInt();
		edge = new ArrayList[n + 1];
		for(int i = 1;i <= n;++i)
		{
			edge[i] = new ArrayList<Integer>();
		}
		for(int i = 0;i < m;++i)
		{
			int u = scan.nextInt();
			int v = scan.nextInt();
			edge[u].add(v);
			edge[v].add(u);
		}
		father = new int[n + 1];
		for(int i = 1;i <= n;++i)
		{
			father[i] = i;
		}
		d = new int[n + 1];
		for(int i = 1;i <= n;++i)
		{
			if(father[i] == i)
			{
				root = i;
				diameter = -1;
				dfs(i, 0, 0);
				diameter = -1;
				dfs(end, 0, 0);
				d[i] = diameter;
			}
		}
		PrintWriter out = new PrintWriter(System.out);
		while(q-- > 0)
		{
			int type = scan.nextInt();
			if(1 == type)
			{
				int x = scan.nextInt();
				int f = findFather(x);
				out.println(d[f]);
			}
			else
			{
				int x = scan.nextInt();
				int y = scan.nextInt();
				unionSet(x, y);
			}
		}
		out.close();
	}

	public static void main(String[] args)
	{
		new Main().foo();
	}

	class MyScanner
	{
	    private byte[] buf = new byte[1024];
	    private int curChar;
	    private int numChars;
	    BufferedInputStream bis = new BufferedInputStream(System.in);

	    public int read()
	    {
	        if (-1 == numChars)
	        {
	        	throw new InputMismatchException();
	        }
	        if (curChar >= numChars)
	        {
	            curChar = 0;
	            try
	            {
	                numChars = bis.read(buf);
	            }
	            catch (IOException e)
	            {
	                throw new InputMismatchException();
	            }
	            if (numChars <= 0)
	            {
	            	return -1;
	            }
	        }
	        return buf[curChar++];
	    }

	    public int nextInt()
	    {
	        int c = read();
	        while (isSpaceChar(c))
	        {
	        	c = read();
	        }
	        int sgn = 1;
	        if (c == '-')
	        {
	            sgn = -1;
	            c = read();
	        }
	        int res = 0;
	        do
	        {
	            if (c < '0' || c > '9')
	            {
	            	throw new InputMismatchException();
	            }
	            res *= 10;
	            res += c - '0';
	            c = read();
	        } while (!isSpaceChar(c));
	        return res * sgn;
	    }

	    public long nextLong()
	    {
	    	int c = read();
	    	while (isSpaceChar(c))
	    	{
	    		c = read();
	    	}
	    	int sgn = 1;
	    	if (c == '-')
	    	{
	    		sgn = -1;
	    		c = read();
	    	}
	    	long res = 0;
	    	do
	    	{
	    		if (c < '0' || c > '9')
	    		{
	    			throw new InputMismatchException();
	    		}
	    		res *= 10;
	    		res += c - '0';
	    		c = read();
	    	} while (!isSpaceChar(c));
	    	return res * sgn;
	    }

	    public double nextDouble()
	    {
	        int c = read();
	        while (isSpaceChar(c))
	        {
	        	c = read();
	        }
	        int sgn = 1;
	        if (c == '-')
	        {
	            sgn = -1;
	            c = read();
	        }
	        double res = 0;
	        while (!isSpaceChar(c) && c != '.')
	        {
	            if (c == 'e' || c == 'E')
	            {
	            	return res * Math.pow(10, nextInt());
	            }
	            if (c < '0' || c > '9')
	            {
	            	throw new InputMismatchException();
	            }
	            res *= 10;
	            res += c & 15;
	            c = read();
	        }
	        if (c == '.')
	        {
	            c = read();
	            double m = 1;
	            while (!isSpaceChar(c))
	            {
	                if (c == 'e' || c == 'E')
	                {
	                	return res * Math.pow(10, nextInt());
	                }
	                if (c < '0' || c > '9')
	                {
	                	throw new InputMismatchException();
	                }
	                m /= 10;
	                res += (c & 15) * m;
	                c = read();
	            }
	        }
	        return res * sgn;
	    }

	    public String next()
	    {
	        int c = read();
	        while (isSpaceChar(c))
	        {
	        	c = read();
	        }
	        StringBuilder res = new StringBuilder();
	        do
	        {
	            res.appendCodePoint(c);
	            c = read();
	        } while (!isSpaceChar(c));
	        return res.toString();
	    }

	    private boolean isSpaceChar(int c)
	    {
	        return ' ' == c || '\n' == c || '\r' == c || '\t' == c || -1 == c;
	    }
	}
}


#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <queue>
#include <map>
#include <functional>
#include <queue>
#include <bitset>
#include <sstream>
#include <set>
#include <iomanip>
#include <string.h>
#include <climits>
#include <unordered_map>

#define INF 1000000000
#define FOR(i, a, b) for(int i=int(a); i<int(b); i++)
#define FORC(cont, it) for(decltype((cont).begin()) it = (cont).begin(); it != (cont).end(); it++)
#define pb push_back
#define endl '\n'

using namespace std;

typedef long long ll;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef vector<ii> vii;
typedef vector<vi> vvi;

#define MOD 1000000007
#define maxN 300005

vi nivel, p, d, G[maxN], diametro;
int N, m, q, nuevodiametro, x, v, y, d1, u;

bool val;

//diametro
int treediameter, nodo;

int bfs_util(int s){
    d.assign(N,INF); d[s] = 0;
    queue<int> q; q.push(s);
    treediameter = 0;
    nodo = s;

    while(!q.empty()){
        u = q.front(); q.pop();
        FOR(j,0,G[u].size()){
            v = G[u][j];
            if(d[v] == INF){
                d[v] = d[u] + 1;

                if(d[v] > treediameter){
                    treediameter = d[v];
                    nodo = v;
                }

                q.push(v);
            }
        }
    }

    return nodo;
}

int bfs(int i){
    d1 = bfs_util(i);
    d1 = bfs_util(d1);
    return treediameter;
}

//DSU
void dsu(){
    nivel.assign(N,0);
    p.assign(N,0);
    diametro.assign(N,-1);

    FOR(i,0,N){
        p[i] = i;
    }
}
int findSet(int i){
    return p[i] == i ? i : p[i] = findSet(p[i]); //PATH COMPRESSION
}
bool sameSet(int i, int j){
    return findSet(i) == findSet(j);
}
void unionSet(int i, int j){
    if(!sameSet(i,j)){
        x = findSet(i);
        y = findSet(j);

        if(val){
            nuevodiametro = (diametro[x]+1)/2 + (diametro[y]+1)/2 + 1 ;
            nuevodiametro = max(diametro[x],nuevodiametro);
            nuevodiametro = max(diametro[y],nuevodiametro);
        }

        if(nivel[x] > nivel[y]){
            p[y] = x;
            if(val)diametro[x] = nuevodiametro;
        }else{
            p[x] = y;
            if(val)diametro[y] = nuevodiametro;
            if(nivel[x] == nivel[y]){
                nivel[y]++;
            }
        }
    }
}

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

    int a, b, c;

    scanf("%d %d %d", &N, &m, &q);
    //Inicializa disjoint sets
    dsu();

    val = false;
    FOR(i,0,m){
        scanf("%d %d", &a, &b);
        a--;
        b--;
        G[a].pb(b);
        G[b].pb(a);
        unionSet(a,b);
    }
    val = true;

    //encuentra los diametros de todos los disjoint sets
    FOR(i,0,N){
        a = findSet(i);
        if(diametro[a] == -1){

            b = bfs(a);
                diametro[a] = b;

            /*
            if(G[a].size()==0){
                diametro[a] = 0;
            }else if(G[a].size() == 1){
                diametro[a] = 1;
            }else{
                b = bfs(a);
                diametro[a] = b;
            }
            */

        }
    }

    FOR(i,0,q){
        scanf("%d", &c);

        if(c == 1){
            scanf("%d", &a);
            a--;
            b = findSet(a);
            printf("%d\n", diametro[b]);
        }else{
            scanf("%d %d", &a, &b);
            a--;
            b--;
            unionSet(a,b);
        }
    }
}


#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <queue>
#include <map>
#include <functional>
#include <queue>
#include <bitset>
#include <sstream>
#include <set>
#include <iomanip>
#include <string.h>
#include <climits>
#include <unordered_map>

#define INF 1000000000
#define FOR(i, a, b) for(int i=int(a); i<int(b); i++)
#define FORC(cont, it) for(decltype((cont).begin()) it = (cont).begin(); it != (cont).end(); it++)
#define pb push_back
#define endl '\n'

using namespace std;

typedef long long ll;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef vector<ii> vii;
typedef vector<vi> vvi;

#define MOD 1000000007
#define maxN 300005

vi nivel, p, d, G[maxN], diametro;
int N, m, q, nuevodiametro, x, v, y, d1, u;

bool val;

//diametro
int treediameter, nodo;

void dfs_util(int s){

    FOR(j,0,G[s].size()){
        int v = G[s][j];
        if(d[v] == INF){
            d[v] = d[s] + 1;

            if(d[v] > treediameter){
                treediameter = d[v];
                nodo = v;
            }

            dfs_util(v);
        }
    }

}

int dfs(int i){
    //cout<<"asta qui"<<endl;

    treediameter = 0;
    nodo = i;
    d.assign(N,INF);
    d[i] = 0;
    dfs_util(i);

    //cout<<"distancia desde "<<i<<" = "<<treediameter<<" "<<nodo<<endl;
    FOR(i,0,7){
        //cout<<d[i]<<" ";
    }//cout<<endl;

    //cout<<"asta qui"<<endl;

    treediameter = 0;
    d.assign(N,INF);
    d[nodo] = 0;
    dfs_util(nodo);

    FOR(i,0,7){
        //cout<<d[i]<<" ";
    }//cout<<endl;

    return treediameter;

}

//DSU
void dsu(){
    nivel.assign(N,0);
    p.assign(N,0);
    diametro.assign(N,-1);

    FOR(i,0,N){
        p[i] = i;
    }
}
int findSet(int i){
    return p[i] == i ? i : p[i] = findSet(p[i]); //PATH COMPRESSION
}
bool sameSet(int i, int j){
    return findSet(i) == findSet(j);
}
void unionSet(int i, int j){
    if(!sameSet(i,j)){
        x = findSet(i);
        y = findSet(j);

        if(val){
            nuevodiametro = (diametro[x]+1)/2 + (diametro[y]+1)/2 + 1 ;
            nuevodiametro = max(diametro[x],nuevodiametro);
            nuevodiametro = max(diametro[y],nuevodiametro);
        }

        if(nivel[x] > nivel[y]){
            p[y] = x;
            if(val)diametro[x] = nuevodiametro;
        }else{
            p[x] = y;
            if(val)diametro[y] = nuevodiametro;
            if(nivel[x] == nivel[y]){
                nivel[y]++;
            }
        }
    }
}

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

    int a, b, c;

    scanf("%d %d %d", &N, &m, &q);
    //Inicializa disjoint sets
    dsu();

    val = false;
    FOR(i,0,m){
        scanf("%d %d", &a, &b);
        a--;
        b--;
        G[a].pb(b);
        G[b].pb(a);
        unionSet(a,b);
    }
    val = true;

    //encuentra los diametros de todos los disjoint sets
    FOR(i,0,N){
        a = findSet(i);
        if(diametro[a] == -1){

            b = dfs(a);
            diametro[a] = b;

        }
        //cout<<i<<" "<<a<<" "<<diametro[a]<<endl;
    }

    FOR(i,0,q){
        scanf("%d", &c);

        if(c == 1){
            scanf("%d", &a);
            a--;
            b = findSet(a);
            printf("%d\n", diametro[b]);
        }else{
            scanf("%d %d", &a, &b);
            a--;
            b--;
            unionSet(a,b);
        }
    }
}


#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <queue>
#include <map>
#include <functional>
#include <queue>
#include <bitset>
#include <sstream>
#include <set>
#include <iomanip>
#include <string.h>
#include <climits>
#include <unordered_map>

#define INF 1000000000
#define FOR(i, a, b) for(int i=int(a); i<int(b); i++)
#define FORC(cont, it) for(decltype((cont).begin()) it = (cont).begin(); it != (cont).end(); it++)
#define pb push_back
#define endl '\n'

using namespace std;

typedef long long ll;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef vector<ii> vii;
typedef vector<vi> vvi;

#define MOD 1000000007
#define maxN 300005

vi nivel, p, d, G[maxN], diametro;
int N, m, q, nuevodiametro, x, v, y, d1, u;

bool val;

//diametro
int treediameter, nodo;

vi guardar;

void dfs_util(int s){

    FOR(j,0,G[s].size()){
        int v = G[s][j];
        if(d[v] == INF){
            d[v] = d[s] + 1;
            guardar.pb(v);

            if(d[v] > treediameter){
                treediameter = d[v];
                nodo = v;
            }

            dfs_util(v);
        }
    }
}

int dfs(int i){

    treediameter = 0;
    nodo = i;
    //d.assign(N,INF); //distancias desde nodo i
    d[i] = 0;
    guardar.pb(nodo);
    dfs_util(i);

    treediameter = 0;
    //d.assign(N,INF);

    FOR(j,0,guardar.size()){
        d[ guardar[j] ]  = INF;
    }guardar.clear();

    guardar.pb(nodo);

    d[nodo] = 0;
    guardar.pb(nodo);
    dfs_util(nodo);

    FOR(j,0,guardar.size()){
        d[ guardar[j] ]  = INF;
    }guardar.clear();

    return treediameter;

}

//DSU
void dsu(){
    nivel.assign(N,0);
    p.assign(N,0);
    diametro.assign(N,-1);
    d.assign(N,INF);

    FOR(i,0,N){
        p[i] = i;
    }
}
int findSet(int i){
    return p[i] == i ? i : p[i] = findSet(p[i]); //PATH COMPRESSION
}
bool sameSet(int i, int j){
    return findSet(i) == findSet(j);
}
void unionSet(int i, int j){
    if(!sameSet(i,j)){
        x = findSet(i);
        y = findSet(j);

        if(val){
            nuevodiametro = (diametro[x]+1)/2 + (diametro[y]+1)/2 + 1 ;
            nuevodiametro = max(diametro[x],nuevodiametro);
            nuevodiametro = max(diametro[y],nuevodiametro);
        }

        if(nivel[x] > nivel[y]){
            p[y] = x;
            if(val)diametro[x] = nuevodiametro;
        }else{
            p[x] = y;
            if(val)diametro[y] = nuevodiametro;
            if(nivel[x] == nivel[y]){
                nivel[y]++;
            }
        }
    }
}

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

    int a, b, c;

    scanf("%d %d %d", &N, &m, &q);
    //Inicializa disjoint sets
    dsu();

    val = false;
    FOR(i,0,m){
        scanf("%d %d", &a, &b);
        a--;
        b--;
        G[a].pb(b);
        G[b].pb(a);
        unionSet(a,b);
    }
    val = true;

    //encuentra los diametros de todos los disjoint sets
    FOR(i,0,N){
        a = findSet(i);
        if(diametro[a] == -1){
            //cout<<"cae en "<<i<<endl;

            b = dfs(a);
            diametro[a] = b;
        }
        //cout<<i<<" "<<a<<" "<<diametro[a]<<endl;
    }

    FOR(i,0,q){
        scanf("%d", &c);

        if(c == 1){
            scanf("%d", &a);
            a--;
            b = findSet(a);
            printf("%d\n", diametro[b]);
        }else{
            scanf("%d %d", &a, &b);
            a--;
            b--;
            unionSet(a,b);
        }
    }
}


#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <queue>
#include <map>
#include <functional>
#include <queue>
#include <bitset>
#include <sstream>
#include <set>
#include <iomanip>
#include <string.h>
#include <climits>
#include <unordered_map>

#define INF 1000000000
#define FOR(i, a, b) for(int i=int(a); i<int(b); i++)
#define FORC(cont, it) for(decltype((cont).begin()) it = (cont).begin(); it != (cont).end(); it++)
#define pb push_back
#define endl '\n'

using namespace std;

typedef long long ll;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef vector<ii> vii;
typedef vector<vi> vvi;

#define MOD 1000000007
#define maxN 300005

vi nivel, p, d, G[maxN], diametro;
int N, m, q, nuevodiametro, x, v, y, d1, u;

bool val;

//diametro
int treediameter, nodo;

int bfs_util(int s){
    d.assign(N,INF); d[s] = 0;
    queue<int> q; q.push(s);
    treediameter = 0;
    nodo = s;

    while(!q.empty()){
        u = q.front(); q.pop();
        FOR(j,0,G[u].size()){
            v = G[u][j];
            if(d[v] == INF){
                d[v] = d[u] + 1;

                if(d[v] > treediameter){
                    treediameter = d[v];
                    nodo = v;
                }

                q.push(v);
            }
        }
    }

    return nodo;
}

int bfs(int i){
    d1 = bfs_util(i);
    d1 = bfs_util(d1);
    return treediameter;
}

//DSU
void dsu(){
    nivel.assign(N,0);
    p.assign(N,0);
    diametro.assign(N,-1);

    FOR(i,0,N){
        p[i] = i;
    }
}
int findSet(int i){
    return p[i] == i ? i : p[i] = findSet(p[i]); //PATH COMPRESSION
}
bool sameSet(int i, int j){
    return findSet(i) == findSet(j);
}
void unionSet(int i, int j){
    if(!sameSet(i,j)){
        x = findSet(i);
        y = findSet(j);

        if(val){
            nuevodiametro = (diametro[x]+1)/2 + (diametro[y]+1)/2 + 1 ;
            nuevodiametro = max(diametro[x],nuevodiametro);
            nuevodiametro = max(diametro[y],nuevodiametro);
        }

        if(nivel[x] > nivel[y]){
            p[y] = x;
            if(val)diametro[x] = nuevodiametro;
        }else{
            p[x] = y;
            if(val)diametro[y] = nuevodiametro;
            if(nivel[x] == nivel[y]){
                nivel[y]++;
            }
        }
    }
}

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

    int a, b, c;

    scanf("%d %d %d", &N, &m, &q);
    //Inicializa disjoint sets
    dsu();

    val = false;
    FOR(i,0,m){
        scanf("%d %d", &a, &b);
        a--;
        b--;
        G[a].pb(b);
        G[b].pb(a);
        unionSet(a,b);
    }
    val = true;

    //encuentra los diametros de todos los disjoint sets
    FOR(i,0,N){
        a = findSet(i);
        if(diametro[a] == -1){

            if(G[a].size()==0){
                diametro[a] = 0;
            }else if(G[a].size() == 1){
                diametro[a] = 1;
            }else{
                b = bfs(a);
                diametro[a] = b;
            }

        }
    }

    FOR(i,0,q){
        scanf("%d", &c);

        if(c == 1){
            scanf("%d", &a);
            a--;
            b = findSet(a);
            printf("%d\n", diametro[b]);
        }else{
            scanf("%d %d", &a, &b);
            a--;
            b--;
            unionSet(a,b);
        }
    }
}


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

const int N = 3e5 + 5;

int n , m , ask;
vector < int > adj[N];
int p[N];
int ans[N];

int mx = 0 , U;
bool done[N];

void dfs(int u , int p , int D){

    if(D > mx){
        mx = D;
        U = u;
    }
    for(auto v : adj[u]){
        if(v != p)
            dfs(v , u , D + 1);
    }
}

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

int sz[N];

void join(int x , int y){
    x = get(x);
    y = get(y);

    if(x == y)return;

    if(sz[y] < sz[x])swap(x , y);

    sz[y] += sz[x];
    p[x] = y;

    ans[y] = max(ans[y] , max(ans[x] , ((ans[y] + 1) >> 1) + ((ans[x] + 1) >> 1) + 1 ));
}

int nextInt() {
    int x = 0, p = 1;
    char c;
    do {
        c = getchar();
    } while (c <= 32);
    if (c == '-') {
        p = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * p;
}

main(){

    n = nextInt();
    m = nextInt();
    ask = nextInt();

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

    int u , v;
    for(int i = 0 ; i < m ; i ++){
        u = nextInt();
        v = nextInt();

        adj[u].push_back(v);
        adj[v].push_back(u);

        join(u , v);
    }

    for(int i = 1 ; i <= n ; i ++){
        int u = get(i);
        if(!done[u]){
            U = u;
            mx = 0;
            dfs(U , 0 , 0);
            mx = 0;
            dfs(U , 0 , 0);
            ans[u] = mx;
            done[u] = 1;
        }
    }

    int type = 0;
    while( ask -- ){
        type = nextInt();
        u    = nextInt();

        if(type == 1){
            printf("%d\n" , ans[get(u)]);
        }
        else {
            v = nextInt();
            join(u , v);
        }
    }

    return 0;
}


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

const int N = 3e5 + 5;

int n , m , ask;
vector < int > adj[N];
int vis[N] , color = 1;
int p[N];
int ans[N];

int dis[N];
queue < int > q;

int pr;

int bfs(int u){

    color ++;
    vis[u] = color;

    q.push(u);

    dis[u] = 0;

    while( !q.empty() ){
        u = q.front();
        q.pop();

        p[u] = pr;
        for(auto v : adj[u]){
            if(vis[v] == color)continue;

            vis[v] = color;
            dis[v] = 1 + dis[u];
            q.push(v);
        }
    }
    return u;
}

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

int sz[N];

void join(int x , int y){
    x = get(x);
    y = get(y);

    if(x == y)return;

    if(sz[y] < sz[x])swap(x , y);

    sz[y] += sz[x];
    p[x] = y;

    ans[y] = max(ans[y] , max(ans[x] , ((ans[y] + 1) >> 1) + ((ans[x] + 1) >> 1) + 1 ));
}

int nextInt() {
    int x = 0, p = 1;
    char c;
    do {
        c = getchar();
    } while (c <= 32);
    if (c == '-') {
        p = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * p;
}

main(){

    n = nextInt();
    m = nextInt();
    ask = nextInt();

    int u , v;
    for(int i = 0 ; i < m ; i ++){
        u = nextInt();
        v = nextInt();

        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    for(int i = 1 ; i <= n ; i ++){
        if(vis[i] != color){
            pr = i;
            ans[ pr ] = dis[ bfs( bfs( i ) ) ];
        }
    }

    int type = 0;
    while( ask -- ){
        type = nextInt();
        u    = nextInt();

        if(type == 1){
            printf("%d\n" , ans[get(u)]);
        }
        else {
            v = nextInt();
            join(u , v);
        }
    }

    return 0;
}


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

const int N = 3e5 + 5;

int n , m , ask;
vector < int > adj[N];
int vis[N] , color = 1;
int p[N];
int ans[N];

void dfs(int u , int pr){
    vis[u] = color;
    p[u] = pr;
    for(auto v : adj[u]){
        if(vis[v] != color){
            dfs(v , pr);
        }
    }
}

int dis[N];
queue < int > q;

int bfs(int u){

    color ++;
    vis[u] = color;

    q.push(u);

    dis[u] = 0;

    while( !q.empty() ){
        u = q.front();
        q.pop();

        for(auto v : adj[u]){
            if(vis[v] == color)continue;

            vis[v] = color;
            dis[v] = 1 + dis[u];
            q.push(v);
        }
    }
    return u;
}

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

void join(int x , int y){
    x = get(x);
    y = get(y);

    if(x == y)return;

    if(rand() & 1)swap(x , y);

    p[x] = y;

    ans[y] = max(ans[y] , max(ans[x] , ((ans[y] + 1) / 2) + ((ans[x] + 1) / 2) + 1 ));
}

main(){

    scanf("%d %d %d" , &n , &m , &ask);

    for(int i = 0 ; i <= n ; i ++)p[i] = i;

    int u , v;
    for(int i = 0 ; i < m ; i ++){
        scanf("%d %d" , &u , &v);

        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    for(int i = 1 ; i <= n ; i ++){
        if(vis[i] != color){
            dfs(i , i);
        }
    }

    color ++;
    for(int i = 1 ; i <= n ; i ++){
        if(vis[i] != color){
            ans[ get(i) ] = dis[ bfs( bfs( i ) ) ];
        }
    }

    int type = 0;
    while( ask -- ){
        scanf("%d" , &type);

        if(type == 1){
            scanf("%d" , &u);

            printf("%d\n" , ans[get(u)]);
        }
        else {
            scanf("%d %d" , &u , &v);
            join(u , v);
        }
    }

    return 0;
}


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

const int N = 3e5 + 5;

int n , m , ask;
vector < int > adj[N];
int p[N];
int ans[N];

int mx = 0 , U;
bool done[N];
int dis[N];

void dfs(int u , int p , int D){

    if(D > mx){
        mx = D;
        U = u;
    }
    for(auto v : adj[u]){
        if(v != p)
            dfs(v , u , D + 1);
    }
}

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

int sz[N];

void join(int x , int y){
    x = get(x);
    y = get(y);

    if(x == y)return;

    if(sz[y] < sz[x])swap(x , y);

    sz[y] += sz[x];
    p[x] = y;

    ans[y] = max(ans[y] , max(ans[x] , ((ans[y] + 1) >> 1) + ((ans[x] + 1) >> 1) + 1 ));
}

queue < int > q;
int vis[N];
int color = 0;

int bfs(int u){

    color ++;
    q.push(u);
    dis[u] = 1;
    vis[u] = color;

    while(!q.empty()){
        u = q.front();
        q.pop();

        for(auto v : adj[u]){
            if(vis[v] != color){
                vis[v] = color;
                dis[v] = 1 + dis[u];
                q.push(v);
            }
        }
    }
    return u;
}

int nextInt() {
    int x = 0, p = 1;
    char c;
    do {
        c = getchar();
    } while (c <= 32);
    if (c == '-') {
        p = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * p;
}

main(){

    n = nextInt();
    m = nextInt();
    ask = nextInt();

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

    int u , v;
    for(int i = 0 ; i < m ; i ++){
        u = nextInt();
        v = nextInt();

        adj[u].push_back(v);
        adj[v].push_back(u);

        join(u , v);
    }

    for(int i = 1 ; i <= n ; i ++){
        int u = get(i);
        if(!done[u]){

            ans[u] = dis[ bfs( bfs( i ) ) ] - 1;

            done[u] = 1;
        }
    }

    int type = 0;
    while( ask -- ){
        type = nextInt();
        u    = nextInt();

        if(type == 1){
            printf("%d\n" , ans[get(u)]);
        }
        else {
            v = nextInt();
            join(u , v);
        }
    }

    return 0;
}


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

const int N = 3e5 + 5;

int n , m , ask;
vector < int > adj[N];
int vis[N] , color = 1;
int p[N];
int ans[N];

int dis[N];
queue < int > q;

int pr;

int bfs(int u){

    color ++;
    vis[u] = color;

    q.push(u);

    dis[u] = 0;

    while( !q.empty() ){
        u = q.front();
        q.pop();

        p[u] = pr;
        for(auto v : adj[u]){
            if(vis[v] == color)continue;

            vis[v] = color;
            dis[v] = 1 + dis[u];
            q.push(v);
        }
    }
    return u;
}

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

void join(int x , int y){
    x = get(x);
    y = get(y);

    if(x == y)return;

    if(rand() & 1)swap(x , y);

    p[x] = y;

    ans[y] = max(ans[y] , max(ans[x] , ((ans[y] + 1) >> 1) + ((ans[x] + 1) >> 1) + 1 ));
}

main(){

    scanf("%d %d %d" , &n , &m , &ask);

    int u , v;
    for(int i = 0 ; i < m ; i ++){
        scanf("%d %d" , &u , &v);

        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    for(int i = 1 ; i <= n ; i ++){
        if(vis[i] != color){
            pr = i;
            ans[ pr ] = dis[ bfs( bfs( i ) ) ];
        }
    }

    int type = 0;
    while( ask -- ){
        scanf("%d" , &type);

        if(type == 1){
            scanf("%d" , &u);

            printf("%d\n" , ans[get(u)]);
        }
        else {
            scanf("%d %d" , &u , &v);
            join(u , v);
        }
    }

    return 0;
}


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

const int N = 3e5 + 5;

int n , m , ask;
vector < int > adj[N];
int vis[N] , color = 1;
int p[N];
int ans[N];

int dis[N];
queue < int > q;

int pr;

int bfs(int u){

    color ++;
    vis[u] = color;

    q.push(u);

    dis[u] = 0;

    while( !q.empty() ){
        u = q.front();
        q.pop();

        p[u] = pr;
        for(auto v : adj[u]){
            if(vis[v] == color)continue;

            vis[v] = color;
            dis[v] = 1 + dis[u];
            q.push(v);
        }
    }
    return u;
}

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

void join(int x , int y){
    x = get(x);
    y = get(y);

    if(x == y)return;

    if(rand() & 1)swap(x , y);

    p[x] = y;

    ans[y] = max(ans[y] , max(ans[x] , ((ans[y] + 1) >> 1) + ((ans[x] + 1) >> 1) + 1 ));
}

int nextInt() {
    int x = 0, p = 1;
    char c;
    do {
        c = getchar();
    } while (c <= 32);
    if (c == '-') {
        p = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * p;
}

main(){

    n = nextInt();
    m = nextInt();
    ask = nextInt();

    int u , v;
    for(int i = 0 ; i < m ; i ++){
        u = nextInt();
        v = nextInt();

        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    for(int i = 1 ; i <= n ; i ++){
        if(vis[i] != color){
            pr = i;
            ans[ pr ] = dis[ bfs( bfs( i ) ) ];
        }
    }

    int type = 0;
    while( ask -- ){
        type = nextInt();
        u    = nextInt();

        if(type == 1){
            printf("%d\n" , ans[get(u)]);
        }
        else {
            v = nextInt();
            join(u , v);
        }
    }

    return 0;
}