#include<iostream>
#include<algorithm>
#include<vector>
#include<utility>
using namespace std;

typedef pair<long long, long long> n_pos;;

n_pos ary[1000005];
vector<n_pos>num_count[1000005];
long long num_factor[1000005];

bool compare(n_pos a, n_pos b)
{
	return a.second < b.second;
}

int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		cin >> ary[i].first;
		ary[i].second = i;
		if (ary[i].first <= m)
			num_count[ary[i].first].push_back(ary[i]);
	}

	for(int i=1;i<=m;i++)
		for (int j = 1; j * i <= m; j++)
			if(!num_count[i].empty())
				num_factor[j * i] += num_count[i].size();

	long long k_max = 0;
	long long l = 1;
	for (int i = 1; i <= m; i++)
		if (num_factor[i] > k_max)
		{
			k_max = num_factor[i];
			l = i;
		}
	vector<n_pos>ans;
	for (int i = 1; i <= m; i++)
		if (l % i == 0)
			ans.insert(ans.end(), num_count[i].begin(), num_count[i].end());
	sort(ans.begin(), ans.end(), compare);
	cout << l << ' ' << k_max << endl;
	for (int i=0;i<ans.size();i++)
		cout << ans[i].second << ' ';
	return 0;
}


#include<iostream>
#include<algorithm>
#include<vector>
#include<utility>
using namespace std;

typedef pair<long long, long long> n_pos;;

n_pos ary[1000005];
vector<n_pos>num_count[1000005];
long long num_factor[1000005];

bool compare(n_pos a, n_pos b)
{
	return a.second < b.second;
}

int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		cin >> ary[i].first;
		ary[i].second = i;
		if (ary[i].first <= m)
			num_count[ary[i].first].push_back(ary[i]);
	}

	for(int i=1;i<=m;i++)
		for (int j = 1; j * i <= m; j++)
			if(!num_count[i].empty())
				num_factor[j * i] += num_count[i].size();

	long long k_max = 0;
	long long l = 1;
	for (int i = 1; i <= m; i++)
		if (num_factor[i] > k_max)
		{
			k_max = num_factor[i];
			l = i;
		}
	vector<n_pos>ans;
	for (int i = 1; i <= m; i++)
		if (l % i == 0)
			ans.insert(ans.end(), num_count[i].begin(), num_count[i].end());
	sort(ans.begin(), ans.end(), compare);
	cout << l << ' ' << k_max << endl;
	for (auto c : ans)
		cout << c.second << ' ';
	return 0;
}


#include<iostream>
#include<algorithm>
#include<utility>
#include<vector>
using namespace std;

pair<long long,long long> ary[1000005];

bool compare(pair<long long, long long>a, pair<long long, long long>b)
{
	return a.first < b.first;
}

bool compare_pos(pair<long long, long long>a, pair<long long, long long>b)
{
	return a.second < b.second;
}

long long gcd(long long a, long long b)
{
	long long r = a % b;
	while (r)
	{
		a = b;
		b = r;
		r = a % b;
	}
	return b;
}

long long lcm(long long a, long long b)
{
	return a * b / gcd(a, b);
}

int main()
{
	long long n, m;
	cin >> n >> m;
	long long l;
	for (int i = 1; i <= n; i++)
	{
		cin >> ary[i].first;
		ary[i].second = i;
	}
	sort(ary + 1, ary + n + 1, compare);
	if(n==1)
		if (ary[1].first > m)
		{
			cout << 1 << ' ' << 0 << endl;
			cout << endl;
			return 0;
		}
		else
		{
			cout << ary[1].first << ' ' << 1 << endl;
			cout << ary[1].second << endl;
			return 0;
		}
	int len;
	l = lcm(ary[1].first, ary[2].first);
	for (len = 2; ary[len].first <= m && len <= n; len++)
	{
		long long tmp = lcm(l, ary[len].first);
		if (tmp > m)
			break;
		else
			l = tmp;
	}
	sort(ary + 1, ary + len, compare_pos);
	cout << l << ' ' << len - 1 << endl;
	for (int i = 1; i < len; i++)
		cout << ary[i].second << ' ';
	return 0;
}


#include<iostream>
#include<algorithm>
#include<utility>
#include<vector>
using namespace std;

pair<long long,long long> ary[1000005];

bool compare(pair<long long, long long>a, pair<long long, long long>b)
{
	return a.first < b.first;
}

bool compare_pos(pair<long long, long long>a, pair<long long, long long>b)
{
	return a.second < b.second;
}

long long gcd(long long a, long long b)
{
	long long r = a % b;
	while (r)
	{
		a = b;
		b = r;
		r = a % b;
	}
	return b;
}

long long lcm(long long a, long long b)
{
	return a * b / gcd(a, b);
}

int main()
{
	long long n, m;
	cin >> n >> m;
	long long l;
	for (int i = 1; i <= n; i++)
	{
		cin >> ary[i].first;
		ary[i].second = i;
	}
	sort(ary + 1, ary + n + 1, compare);
	if (ary[1].first > m)
	{
		cout << 1 << ' ' << 0 << endl;
		cout << endl;
		return 0;
	}
	if (n == 1)
	{
		cout << ary[1].first << ' ' << 1 << endl;
		cout << ary[1].second << endl;
		return 0;
	}
	int len;
	l = lcm(ary[1].first, ary[2].first);
	vector<pair<long long, long long>>ans;
	ans.push_back(ary[1]);
	for (len = 2; ary[len].first <= m && len <= n; len++)
	{
		long long tmp = lcm(l, ary[len].first);
		if (tmp > m)
			continue;
		else
		{
			l = tmp;
			ans.push_back(ary[len]);
		}
	}
	sort(ans.begin(), ans.end(), compare_pos);
	cout << l << ' ' << ans.size() << endl;
	for (auto c : ans)
		cout << c.second << ' ';
	return 0;
}


#include<iostream>
#include<cstdio>

using namespace std ;

long long a[1000005] ;
int num[1000005] ;
int maxi = 0 ;
int maxnum = 0 ;

int main()
{
	int n,m,i,j ;
	for (i = 0 ; i < 1000005 ; i++ )
		num[i] = 0 ;

	scanf("%d%d",&n,&m) ;
	for ( i = 1 ; i <= n ; i++)
	{
		scanf("%d",&a[i]) ;
		if ( a[i] < 1000005 )
			num[a[i]]++ ;

	}

	for ( i = m ; i >= 1 ; i-- )
	{
		for ( j = 2*i ; j <= m ; j += i )
		{
			num[j] += num[i] ;
		}

	}

	for ( i = 1 ; i <= m ; i++)
	{
		if ( num[i] > maxi )
			maxi = num[i] , maxnum = i ;

	}

	if ( maxnum == 0 )
	{
		printf("1 0\n") ;
		return 0 ;
	}

	printf("%d %d\n",maxnum,maxi) ;

	for ( i = 1 ; i <= n ; i++ )
	{
		if ( maxnum % a[i] == 0 )
			printf("%d ", i) ;

	}
	return 0 ;
}


#include<iostream>
#include<cstdio>

using namespace std ;

long long a[1000005] ;
int num[1000005] ;
int maxi = 0 ;
int maxnum = 0 ;

int main()
{
	int n,m,i,j ;
	for (i = 0 ; i < 1000005 ; i++ )
		num[i] = 0 ;

	scanf("%d%d",&n,&m) ;
	for ( i = 1 ; i <= n ; i++)
	{
		scanf("%d",&a[i]) ;
		for( j = a[i] ; j <= m ; j += a[i])
			num[j] ++ ;

	}

	for ( i = 1 ; i <= m ; i++)
	{
		if ( num[i] > maxi )
			maxi = num[i] , maxnum = i ;

	}

	if ( maxnum == 0 )
		printf("1 0\n") , return 0 ;

	printf("%d %d\n",maxnum,maxi) ;

	for ( i = 1 ; i <= n ; i++ )
	{
		if ( maxnum % a[i] == 0 )
			printf("%d ", i) ;

	}
	return 0 ;
}


#include<iostream>
#include<cstdio>

using namespace std ;

long long a[1000005] ;
int num[1000005] ;
int maxi = 0 ;
int maxnum = 0 ;

int main()
{
	int n,m,i,j ;
	for (i = 0 ; i < 1000005 ; i++ )
		num[i] = 0 ;

	scanf("%d%d",&n,&m) ;
	for ( i = 1 ; i <= n ; i++)
	{
		scanf("%d",&a[i]) ;
		for( j = a[i] ; j <= m ; j += a[i])
			num[j] ++ ;

	}

	for ( i = 1 ; i <= m ; i++)
	{
		if ( num[i] > maxi )
			maxi = num[i] , maxnum = i ;

	}

	if ( maxnum == 0 )
	{
		printf("1 0\n") ;
		return 0 ;
	}

	printf("%d %d\n",maxnum,maxi) ;

	for ( i = 1 ; i <= n ; i++ )
	{
		if ( maxnum % a[i] == 0 )
			printf("%d ", i) ;

	}
	return 0 ;
}


#include <bits/stdc++.h>
#define pb push_back
#define pii pair<int, int>
#define nyan "(=^･ω･^=)"
#define read_input         freopen("in.txt","r", stdin)
#define print_output       freopen("out.txt","w", stdout)
typedef long long ll;
typedef long double ld;
using namespace std;

const int maxn = 3e5+10;

struct query {
    int typ, u, v;
}; vector<query> Q;

vector<int> adj[maxn];
int par[maxn], sub[maxn];
pii centroid[maxn];
int visited[maxn], dpn[maxn][3];

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

void merge(int u, int v) {
    if(find(u) == find(v)) return;

    pii a = centroid[find(u)];
    pii b = centroid[find(v)];

    if(a.first + a.second < b.first + b.second) swap(a, b), swap(u, v);

    int q1 = a.first + b.first + 1;
    int q2 = a.first + a.second;

    pii c;
    if(q2 > q1) c = a;
    else c = pii(a.first, max(b.first + 1, a.second));

    if(c.first < c.second) swap(c.first, c.second);

    par[find(v)] = find(u);
    centroid[find(u)] = c;
}

void dfs(int u, int par) {
    visited[u] = 1;
    dpn[u][0] = dpn[u][1] = 0;

    for(auto v: adj[u]) {
        if(v == par) continue;
        dfs(v, u);

        if(dpn[v][0]+1 >= dpn[u][0]) {
            dpn[u][1] = dpn[u][0];
            dpn[u][0] = dpn[v][0] + 1;
        }
        else dpn[u][1] = max(dpn[u][1], dpn[v][0]+1);
    }
}

void calc(int u, int par) {
    sub[u] = 1;
    for(auto v : adj[u]) {
        if(v == par) continue;
        calc(v, u);
        sub[u] += sub[v];
    }
}

int get(int u, int par, int sz) {
    for(auto v : adj[u]) {
        if(v == par) continue;
        if(sub[v] > sz) return get(v, u, sz);
    } return u;
}

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

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

    for(int i = 1, u, v; i <= m; i++) {
        scanf("%d %d", &u, &v); //cin >> u >> v;

        par[find(v)] = find(u);
        adj[u].pb(v);
        adj[v].pb(u);
    }
    for(int i = 1; i <= n; i++) {
        if(!visited[i]) {
            calc(i, 0);
            int c = get(i, 0, sub[i]/2);

            dfs(c, 0);
        }
    }

    for(int i = 1; i <= n; i++) {
        int sum = dpn[i][0] + dpn[i][1];
        pii t = centroid[find(i)];

        if(sum > t.first + t.second)
            t = pii(dpn[i][0], dpn[i][1]);
        else if(sum == t.first + t.second) {
            if(dpn[i][0] < t.first) t = pii(dpn[i][0], dpn[i][1]);
        }

        centroid[find(i)] = t;
    }

    //for(int i = 1; i <= n; i++)
    //    cout << centroid[find(i)].first << " " << centroid[find(i)].second << endl;
    //cout << endl;

    for(int i = 1; i <= q; i++) {
        int k, u, v; scanf("%d", &k); //cin >> k;
        if(k == 1) scanf("%d", &u), Q.pb({k, u, 0}); //cin >> u, Q.pb({k, u, 0});
        else scanf("%d %d", &u, &v), Q.pb({k, u, v}); //cin >> u >> v, Q.pb({k, u, v});
    }

    for(auto q : Q) {
    //while(1) {
        if(q.typ == 1) printf("%d\n", centroid[find(q.u)].first + centroid[find(q.u)].second); //cout << centroid[find(q.u)].first + centroid[find(q.u)].second << endl;
        else merge(q.u, q.v);

        //if(q.typ == 2) merge(q.u, q.v);
        /*int u, v; cin >> u >> v;
        merge(u, v);

        for(int i = 1; i <= n; i++)
            cout << centroid[find(i)].first << " " << centroid[find(i)].second << endl;
        cout << endl;*/
    }

    return 0;
}


#include <bits/stdc++.h>
#define pb push_back
#define pii pair<int, int>
#define nyan "(=^･ω･^=)"
#define read_input         freopen("in.txt","r", stdin)
#define print_output       freopen("out.txt","w", stdout)
typedef long long ll;
typedef long double ld;
using namespace std;

const int maxn = 3e5+10;

struct query {
    int typ, u, v;
}; vector<query> Q;

vector<int> adj[maxn];
int par[maxn], sub[maxn];
pii centroid[maxn];
int visited[maxn], dpn[maxn][3];

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

void merge(int u, int v) {
    if(find(u) == find(v)) return;

    pii a = centroid[find(u)];
    pii b = centroid[find(v)];

    if(a.first + a.second < b.first + b.second) swap(a, b), swap(u, v);

    int q1 = a.first + b.first + 1;
    int q2 = a.first + a.second;

    pii c;
    if(q2 > q1) c = a;
    else c = pii(a.first, max(b.first + 1, a.second));

    if(c.first < c.second) swap(c.first, c.second);

    par[find(v)] = find(u);
    centroid[find(u)] = c;
}

void dfs(int u, int par) {
    visited[u] = 1;
    dpn[u][0] = dpn[u][1] = 0;

    for(auto v: adj[u]) {
        if(v == par) continue;
        dfs(v, u);

        if(dpn[v][0]+1 >= dpn[u][0]) {
            dpn[u][1] = dpn[u][0];
            dpn[u][0] = dpn[v][0] + 1;
        }
        else dpn[u][1] = max(dpn[u][1], dpn[v][0]+1);
    }
}

void calc(int u, int par) {
    sub[u] = 1;
    for(auto v : adj[u]) {
        if(v == par) continue;
        calc(v, u);
        sub[u] += sub[v];
    }
}

int get(int u, int par, int sz) {
    for(auto v : adj[u]) {
        if(v == par) continue;
        if(sub[v] > sz) return get(v, u, sz);
    } return u;
}

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

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

    for(int i = 1, u, v; i <= m; i++) {
        cin >> u >> v;

        par[find(v)] = find(u);
        adj[u].pb(v);
        adj[v].pb(u);
    }
    for(int i = 1; i <= n; i++) {
        if(!visited[i]) {
            calc(i, 0);
            int c = get(i, 0, sub[i]/2);

            dfs(c, 0);
        }
    }

    for(int i = 1; i <= n; i++) {
        int sum = dpn[i][0] + dpn[i][1];
        pii t = centroid[find(i)];

        if(sum > t.first + t.second)
            t = pii(dpn[i][0], dpn[i][1]);
        else if(sum == t.first + t.second) {
            if(dpn[i][0] < t.first) t = pii(dpn[i][0], dpn[i][1]);
        }

        centroid[find(i)] = t;
    }

    //for(int i = 1; i <= n; i++)
    //    cout << centroid[find(i)].first << " " << centroid[find(i)].second << endl;
    //cout << endl;

    for(int i = 1; i <= q; i++) {
        int k, u, v; cin >> k;
        if(k == 1) cin >> u, Q.pb({k, u, 0});
        else cin >> u >> v, Q.pb({k, u, v});
    }

    for(auto q : Q) {
    //while(1) {
        if(q.typ == 1) cout << centroid[find(q.u)].first + centroid[find(q.u)].second << endl;
        else merge(q.u, q.v);

        if(q.typ == 2) merge(q.u, q.v);
        /*int u, v; cin >> u >> v;
        merge(u, v);

        for(int i = 1; i <= n; i++)
            cout << centroid[find(i)].first << " " << centroid[find(i)].second << endl;
        cout << endl;*/
    }

    return 0;
}


#include <map>
#include <unordered_map>
#include <set>
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cmath>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <bitset>
#define PI acos(-1.0)
#define INF 100000000
#define llINF 923372036854775807
#define EPS 1e-9
#define sz(v)        static_cast<int>((v).size())
#define pb(...)      push_back(__VA_ARGS__)
#define mp(x, y)     make_pair((x), (y))
#define clr(x) memset(x, 0, sizeof(x))
#define clr1(x) memset(x, INF, sizeof(x))
#define dREP(i, a, b) for (int i = (a); i >= (b); --i)
#define REP(i, a, b) for (int i = (a); i < (b); ++i)
#define DFS_WHITE -1
#define DFS_BLACK 1
#define DFS_GRAY 2
#define NOT(x)  (1^(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> ii;
typedef vector<ii> vii;
typedef vector<int> vi;
typedef vector<vi> Graph;
typedef map<int, int>::iterator it_type;
typedef vector<int> row;
typedef vector<row> matrix;
int MOD  = 1000000007;
inline int toInt(string s){int v; istringstream sin(s);sin>>v;return v;}
inline ll toll(string s){ll v; istringstream sin(s);sin>>v;return v;}
template<class T> inline string toString(T x) { ostringstream sout; sout << x; return sout.str();}
#define rep(i, v) for(int i=0;i<sz(v);++i)
#define MAX 1000002
#define LSOne(S) (S & (-S))

class UnionFind {
private:
    vi p, rank, setSize;
    int numSets;
public:
    UnionFind(int N) {
        setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
        p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
    int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
    bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
    void unionSet(int i, int j) {
        if (!isSameSet(i, j)) { numSets--;
            int x = findSet(i), y = findSet(j);
            if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
            else                   { p[x] = y; setSize[y] += setSize[x];
                if (rank[x] == rank[y]) rank[y]++; } } }
    int numDisjointSets() { return numSets; }
    int sizeOfSet(int i) { return setSize[findSet(i)]; }
};
Graph g;
int dist = 0;
int furthest = 0;
int longest[MAX];
int done[MAX];
void dfs(int u,int c,int p = -1){
    done[u] = 1;
    if (c >= dist) {
        dist = c;
        furthest = u;
    }
    for (int v : g[u]) {
        if (p != v) {
            dfs(v, c+1, u);
        }
    }
}
void getDiameter(int u){
    dist = 0;
    furthest = 0;
    dfs(u, 0);
    dfs(furthest, 0);
}

int main() {
    ios_base::sync_with_stdio(0);cin.tie(0);
    //freopen("grant.in" , "r", stdin);
    //freopen("grant.out" , "w", stdout);
    int n,m,q;
    cin>>n>>m>>q;
    UnionFind uf(n);
    g.assign(n, vi());
    int tempU = -1;
    for(int i = 0 ; i < m ;i++){
        int u,v;
        cin>>u>>v;
        u--,v--;
        tempU = u;
        g[u].pb(v);
        g[v].pb(u);
        uf.unionSet(u, v);
    }
    for(int i = 0 ; i < n ; i++){
        if (!done[i]) {
            getDiameter(i);
            longest[uf.findSet(i)] = dist;
        }
    }
    while (q--) {
        int c,u,v;
        cin>>c>>u;
        u--;
        if (c == 1) {
            cout<<longest[uf.findSet(u)]<<endl;
            continue;
        }
        cin>>v;
        v--;
        if(uf.isSameSet(u, v)){
            continue;
        }
        int p1 = uf.findSet(u),p2 = uf.findSet(v);
        int sz1 = (longest[p1]+1)/2, sz2 = (longest[p2]+1)/2;
        uf.unionSet(p1, p2);
        int p = uf.findSet(p1);
        longest[p] = max(sz1 + sz2 + 1,max(longest[p1],longest[p2]));
    }
    return 0;
}


#include <map>
#include <unordered_map>
#include <set>
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cmath>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <bitset>
#define PI acos(-1.0)
#define INF 100000000
#define llINF 923372036854775807
#define EPS 1e-9
#define sz(v)        static_cast<int>((v).size())
#define pb(...)      push_back(__VA_ARGS__)
#define mp(x, y)     make_pair((x), (y))
#define clr(x) memset(x, 0, sizeof(x))
#define clr1(x) memset(x, INF, sizeof(x))
#define dREP(i, a, b) for (int i = (a); i >= (b); --i)
#define REP(i, a, b) for (int i = (a); i < (b); ++i)
#define DFS_WHITE -1
#define DFS_BLACK 1
#define DFS_GRAY 2
#define NOT(x)  (1^(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> ii;
typedef vector<ii> vii;
typedef vector<int> vi;
typedef vector<vi> Graph;
typedef map<int, int>::iterator it_type;
typedef vector<int> row;
typedef vector<row> matrix;
int MOD  = 1000000007;
inline int toInt(string s){int v; istringstream sin(s);sin>>v;return v;}
inline ll toll(string s){ll v; istringstream sin(s);sin>>v;return v;}
template<class T> inline string toString(T x) { ostringstream sout; sout << x; return sout.str();}
#define rep(i, v) for(int i=0;i<sz(v);++i)
#define MAX 1000002
#define LSOne(S) (S & (-S))

class UnionFind {
private:
    vi p, rank, setSize;
    int numSets;
public:
    UnionFind(int N) {
        setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
        p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
    int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
    bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
    void unionSet(int i, int j) {
        if (!isSameSet(i, j)) { numSets--;
            int x = findSet(i), y = findSet(j);
            if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
            else                   { p[x] = y; setSize[y] += setSize[x];
                if (rank[x] == rank[y]) rank[y]++; } } }
    int numDisjointSets() { return numSets; }
    int sizeOfSet(int i) { return setSize[findSet(i)]; }
};
Graph g;
int dist = 0;
int furthest = 0;
bool vis[MAX];
void dfs(int u,int c){
    if (c > dist) {
        dist = c;
        furthest = u;
    }
    vis[u] = 1;
    for (int v : g[u]) {
        if (!vis[v]) {
            dfs(v, c+1);
        }
    }
}
int longest[MAX];
int main() {
    ios_base::sync_with_stdio(0);cin.tie(0);
    //freopen("grant.in" , "r", stdin);
    //freopen("grant.out" , "w", stdout);
    int n,m,q;
    cin>>n>>m>>q;
    UnionFind uf(n);
    g.assign(n, vi());
    int tempU = -1;
    for(int i = 0 ; i < m ;i++){
        int u,v;
        cin>>u>>v;
        u--,v--;
        tempU = u;
        g[u].pb(v);
        g[v].pb(u);
        uf.unionSet(u, v);
    }
    if (m) {
        dfs(tempU, 0);
    }
    memset(vis, 0, sizeof(vis));
    if (m) {
        dfs(furthest, 0);
        longest[uf.findSet(tempU)] = dist;
    }
    while (q--) {
        int c,u,v;
        cin>>c>>u;
        u--;
        if (c == 1) {
            cout<<longest[uf.findSet(u)]<<endl;
            continue;
        }
        cin>>v;
        v--;
        if(uf.isSameSet(u, v)){
            continue;
        }
        int p1 = uf.findSet(u),p2 = uf.findSet(v);
        int sz1 = (longest[p1]+1)/2, sz2 = (longest[p2]+1)/2;
        uf.unionSet(p1, p2);
        int p = uf.findSet(p1);
        longest[p] = max(sz1 + sz2 + 1,max(longest[p1],longest[p2]));
    }
    return 0;
}


#include <map>
#include <unordered_map>
#include <set>
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cmath>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <bitset>
#define PI acos(-1.0)
#define INF 100000000
#define llINF 923372036854775807
#define EPS 1e-9
#define sz(v)        static_cast<int>((v).size())
#define pb(...)      push_back(__VA_ARGS__)
#define mp(x, y)     make_pair((x), (y))
#define clr(x) memset(x, 0, sizeof(x))
#define clr1(x) memset(x, INF, sizeof(x))
#define dREP(i, a, b) for (int i = (a); i >= (b); --i)
#define REP(i, a, b) for (int i = (a); i < (b); ++i)
#define DFS_WHITE -1
#define DFS_BLACK 1
#define DFS_GRAY 2
#define NOT(x)  (1^(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> ii;
typedef vector<ii> vii;
typedef vector<int> vi;
typedef vector<vii> Graph;
typedef map<int, int>::iterator it_type;
typedef vector<int> row;
typedef vector<row> matrix;
int MOD  = 1000000007;
inline int toInt(string s){int v; istringstream sin(s);sin>>v;return v;}
inline ll toll(string s){ll v; istringstream sin(s);sin>>v;return v;}
template<class T> inline string toString(T x) { ostringstream sout; sout << x; return sout.str();}
#define rep(i, v) for(int i=0;i<sz(v);++i)
#define MAX 1000002
#define LSOne(S) (S & (-S))

class UnionFind {
private:
    vi p, rank, setSize;
    int numSets;
public:
    UnionFind(int N) {
        setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
        p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
    int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
    bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
    void unionSet(int i, int j) {
        if (!isSameSet(i, j)) { numSets--;
            int x = findSet(i), y = findSet(j);
            if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
            else                   { p[x] = y; setSize[y] += setSize[x];
                if (rank[x] == rank[y]) rank[y]++; } } }
    int numDisjointSets() { return numSets; }
    int sizeOfSet(int i) { return setSize[findSet(i)]; }
};
int longest[MAX];
int main() {
    ios_base::sync_with_stdio(0);cin.tie(0);
    //freopen("grant.in" , "r", stdin);
    //freopen("grant.out" , "w", stdout);
    int n,m,q;
    cin>>n>>m>>q;
    UnionFind uf(n);
    for(int i = 0 ; i < m ;i++){
        int u,v;
        cin>>u>>v;
        u--,v--;
        if (uf.isSameSet(u, v)) {
            continue;
        }else{
            int p1 = uf.findSet(u),p2 = uf.findSet(v);
            int sz1 = (longest[p1]+1)/2, sz2 = (longest[p2]+1)/2;
            uf.unionSet(p1, p2);
            int p = uf.findSet(p1);
            longest[p] = sz1 + sz2 + 1;
        }
    }
    while (q--) {
        int c,u,v;
        cin>>c>>u;
        u--;
        if (c == 1) {
            cout<<longest[uf.findSet(u)];
            continue;
        }
        cin>>v;
        int p1 = uf.findSet(u),p2 = uf.findSet(v);
        int sz1 = (longest[p1]+1)/2, sz2 = (longest[p2]+1)/2;
        uf.unionSet(p1, p2);
        int p = uf.findSet(p1);
        longest[p] = sz1 + sz2 + 1;
    }
    return 0;
}


#include <bits/stdc++.h>

#include <ext/pb_ds/detail/standard_policies.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("Ofast")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4")

#define ll long long
#define ld long double
#define pb push_back
#define F first
#define S second
#define endl '\n'
//#define int long long

using namespace std;

using namespace __gnu_pbds;

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

const int N = 5e5+100;
const int M = 20;
const ll mod = 1e9+7;
const ll MOD = 998244353;
const ld eps = 0.000000001;
const int P = 1336;
const ll inf = 1e17;

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

vector <int> g[N];
int z[N], pr[N], u[N];
pair <int, int> ma[N];

int maxx = 0, ver = 0;

void upd(int v, int zn)
{
    if (ma[v].F <= zn)
    {
        ma[v].S = ma[v].F;
        ma[v].F = zn;
    }
    else if (ma[v].S < zn) ma[v].S = zn;
}

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

void unite(int a, int b)
{
    a = get(a);
    b = get(b);
    if (a == b) return;
    if (ma[b] > ma[a]) swap(a, b);
    upd(a, ma[b].F + 1);
    pr[b] = a;

}

void DFS(int v, int pred)
{
    ma[v] = {0, 0};
    u[v] = 1;
    for(auto to: g[v])
    {
        if (to == pred) continue;
        DFS(to, v);
        upd(v, ma[to].F + 1);
    }
}

void dfs(int v, int pred, int z)
{
    upd(v, z);
    for(auto to: g[v])
    {
        if (to == pred) continue;
        if (ma[to].F+1 == ma[v].F) dfs(to, v, max(z, ma[v].S + 1));
        else dfs(to, v, max(z, ma[v].F + 1));
    }
    if (maxx > ma[v].F)
    {
        maxx = ma[v].F;
        ver = v;
    }
}

void prisv(int v, int pred)
{
    pr[v] = ver;
    for(auto to: g[v])
    {
        if (to == pred) continue;
        prisv(to, v);
    }
}

int32_t main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    srand(time(0));

    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);

    int n, m, q;
    cin >> n >> m >> q;
    for(int i = 0; i<n; i++)
    {
        pr[i] = i;
    }
    for(int i = 0; i<m; i++)
    {
        int x, y;
        cin >> x >> y;
        x--; y--;
        g[x].pb(y);
        g[y].pb(x);
        unite(x, y);
    }
    for(int i = 0; i<n; i++)
    {
        if (g[i].size() && u[i] == 0)
        {
            maxx = inf; ver = i;
            DFS(i, i);
            dfs(i, i, 0);
            prisv(i, i);
        }
    }
    for(int i = 0; i<q; i++)
    {
        int t;
        cin >> t;
        if (t == 1)
        {
            int x;
            cin >> x;
            x--;
            x = get(x);
            cout << ma[x].F + ma[x].S << endl;
        }
        else
        {
            int x, y;
            cin >> x >> y;
            x--; y--;
            unite(x, y);
        }
    }
}


#include <bits/stdc++.h>

#include <ext/pb_ds/detail/standard_policies.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("Ofast")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4")

#define ll long long
#define ld long double
#define pb push_back
#define F first
#define S second
#define endl '\n'
//#define int long long

using namespace std;

using namespace __gnu_pbds;

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

const int N = 5e5+100;
const int M = 20;
const ll mod = 1e9+7;
const ll MOD = 998244353;
const ld eps = 0.000000001;
const int P = 1336;
const ll inf = 1e17;

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

vector <int> g[N];
int z[N], pr[N], u[N];
pair <int, int> ma[N];

int maxx = 0, ver = 0;

void upd(int v, int zn)
{
    if (ma[v].F <= zn)
    {
        ma[v].S = ma[v].F;
        ma[v].F = zn;
    }
    else if (ma[v].S < zn) ma[v].S = zn;
}

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

void unite(int a, int b)
{
    a = get(a);
    b = get(b);
    if (a == b) return;
    if (ma[b].F > ma[a].F + 1) swap(a, b);
    else if (ma[b].F == ma[a].F + 1 && ma[b].S >= ma[a].S) swap(a, b);
    upd(a, ma[b].F + 1);
    pr[b] = a;

}

void DFS(int v, int pred)
{
    ma[v] = {0, 0};
    u[v] = 1;
    for(auto to: g[v])
    {
        if (to == pred) continue;
        DFS(to, v);
        upd(v, ma[to].F + 1);
    }
}

void dfs(int v, int pred, int z)
{
    upd(v, z);
    for(auto to: g[v])
    {
        if (to == pred) continue;
        if (ma[to].F+1 == ma[v].F) dfs(to, v, max(z, ma[v].S + 1));
        else dfs(to, v, max(z, ma[v].F + 1));
    }
    if (maxx > ma[v].F)
    {
        maxx = ma[v].F;
        ver = v;
    }
}

void prisv(int v, int pred)
{
    pr[v] = ver;
    for(auto to: g[v])
    {
        if (to == pred) continue;
        prisv(to, v);
    }
}

int32_t main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    srand(time(0));

    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);

    int n, m, q;
    cin >> n >> m >> q;
    for(int i = 0; i<n; i++)
    {
        pr[i] = i;
    }
    for(int i = 0; i<m; i++)
    {
        int x, y;
        cin >> x >> y;
        x--; y--;
        g[x].pb(y);
        g[y].pb(x);
        unite(x, y);
    }
    for(int i = 0; i<n; i++)
    {
        if (g[i].size() && u[i] == 0)
        {
            maxx = inf; ver = i;
            DFS(i, i);
            dfs(i, i, 0);
            prisv(i, i);
        }
    }
    for(int i = 0; i<q; i++)
    {
        int t;
        cin >> t;
        if (t == 1)
        {
            int x;
            cin >> x;
            x--;
            x = get(x);
            cout << ma[x].F + ma[x].S << endl;
        }
        else
        {
            int x, y;
            cin >> x >> y;
            x--; y--;
            unite(x, y);
        }
    }
}


#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <cmath>

#define M int(1e5) * 4
#define S second
#define F first
#define ll long long
#define l long
#define pb push_back

using namespace std;

int par[M], size[M], com[M];
vector <int> adj[M];
bool flag[M];
int n, m, q, mx;

void dfs(int a, int k){
	flag[a] = true;
	mx = max(mx, k);
	for(int i = 0; i < adj[a].size(); i++){
		if(!flag[adj[a][i]])
			dfs(adj[a][i], k + 1);
	}
}

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

void merge(int a, int b){
	int pa = find(a), pb = find(b);
	if(pa == pb) return;
	if(size[pa] > size[pb]){
		par[pb] = pa;
		size[pa] += size[pb];
	}
	else{
		par[pa] = pb;
		size[pb] += size[pa];
	}
}

int main(){
	ios_base::sync_with_stdio(false);
	cin >> n >> m >> q;
	for(int i = 1; i <= n; i++){
		par[i] = i;
		size[i] = 1;
	}
	for(int i = 0; i < m; i++){
		int a, b;
		cin >> a >> b;
		adj[a].pb(b);
		adj[b].pb(a);
		merge(a, b);
	}
	for(int i = 1; i <= n; i++){
		if(!flag[i]){
			dfs(i, 0);
			com[find(i)] = mx;
			mx = 0;
		}
	}
	for(int i = 0; i < q; i++){
		int a; cin >> a;
		if(a == 1){
			int b; cin >> b;
			cout << com[find(b)] << endl;
		}
		else{
			int b, c; cin >> b >> c;
			int pb = find(b), pc = find(c);
			if(pb != pc){
				int t = max(com[pb], max(com[pc], int(ceil(float(com[pb]) / 2) + ceil(float(com[pc]) / 2) + 1)));
				merge(b, c);
				com[find(b)] = t;
			}
		}
	}
    return 0;
}


#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <cmath>

#define M int(1e5) * 4
#define S second
#define F first
#define ll long long
#define l long
#define pb push_back

using namespace std;

int par[M], size[M], com[M];
vector <int> adj[M];
bool flag[M];
int n, m, q, mx;

void dfs(int a, int k){
	flag[a] = true;
	mx = max(mx, k);
	for(int i = 0; i < adj[a].size(); i++){
		if(!flag[adj[a][i]])
			dfs(adj[a][i], k + 1);
	}
}

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

void merge(int a, int b){
	int pa = find(a), pb = find(b);
	if(pa == pb) return;
	if(size[pa] > size[pb]){
		par[pb] = pa;
		size[pa] += size[pb];
	}
	else{
		par[pa] = pb;
		size[pb] += size[pa];
	}
}

int main(){
	ios_base::sync_with_stdio(false);
	cin >> n >> m >> q;
	for(int i = 1; i <= n; i++){
		par[i] = i;
		size[i] = 1;
	}
	for(int i = 0; i < m; i++){
		int a, b;
		cin >> a >> b;
		adj[a].pb(b);
		adj[b].pb(a);
		merge(a, b);
	}
	for(int i = 1; i <= n; i++){
		if(!flag[i]){
			int ma = 0, mb = 0;
			flag[i] = true;
			for(int j = 0; j < adj[i].size(); j++){
				dfs(adj[i][j], 1);
				if(mx >= ma){
					mb = ma;
					ma = mx;
				}
				else if(mx > mb){
					mb = mx;
				}
				mx = 0;
			}
			// dfs(i, 0);
			com[find(i)] = ma + mb;
		}
	}
	for(int i = 0; i < q; i++){
		int a; cin >> a;
		if(a == 1){
			int b; cin >> b;
			cout << com[find(b)] << endl;
		}
		else{
			int b, c; cin >> b >> c;
			int pb = find(b), pc = find(c);
			if(pb != pc){
				int t = max(com[pb], max(com[pc], int(ceil(float(com[pb]) / 2) + ceil(float(com[pc]) / 2) + 1)));
				merge(b, c);
				com[find(b)] = t;
			}
		}
	}
    return 0;
}


#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <cmath>

#define M int(1e5) * 4
#define S second
#define F first
#define ll long long
#define l long
#define pb push_back

using namespace std;

int par[M], size[M], com[M];
vector <int> adj[M];
bool flag[M];
bool flag1[M];
int n, m, q, mx, node;

void dfs(int a, int k){
	// cout << "    " << a << " " << k << endl;
	flag[a] = true;
	if(k > mx){
		mx = k;
		node = a;
	}
	for(int i = 0; i < adj[a].size(); i++){
		if(!flag[adj[a][i]])
			dfs(adj[a][i], k + 1);
	}
}

void dfs1(int a, int k){
	// cout << "    " << a << " " << k << endl;
	flag1[a] = true;
	if(k > mx){
		mx = k;
		node = a;
	}
	for(int i = 0; i < adj[a].size(); i++){
		if(!flag1[adj[a][i]])
			dfs1(adj[a][i], k + 1);
	}
}

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

void merge(int a, int b){
	int pa = find(a), pb = find(b);
	if(pa == pb) return;
	if(size[pa] > size[pb]){
		par[pb] = pa;
		size[pa] += size[pb];
	}
	else{
		par[pa] = pb;
		size[pb] += size[pa];
	}
}

int main(){
	ios_base::sync_with_stdio(false);
	cin >> n >> m >> q;
	for(int i = 1; i <= n; i++){
		par[i] = i;
		size[i] = 1;
	}
	for(int i = 0; i < m; i++){
		int a, b;
		cin >> a >> b;
		adj[a].pb(b);
		adj[b].pb(a);
		merge(a, b);
	}
	for(int i = 1; i <= n; i++){
		if(!flag[i]){
			node = i;
			dfs(i, 0);
			// cout << mx << "          " << node << endl;
			mx = 0;
			dfs1(node, 0);
			// cout << mx << "     -----     " << node << endl;
			com[find(i)] = mx;
			mx = 0;
		}
	}
	for(int i = 0; i < q; i++){
		int a; cin >> a;
		if(a == 1){
			int b; cin >> b;
			cout << com[find(b)] << endl;
		}
		else{
			int b, c; cin >> b >> c;
			int pb = find(b), pc = find(c);
			if(pb != pc){
				int t = max(com[pb], max(com[pc], int(ceil(float(com[pb]) / 2) + ceil(float(com[pc]) / 2) + 1)));
				merge(b, c);
				com[find(b)] = t;
			}
		}
	}
    return 0;
}


//Siddharth Yadav
#include <bits/stdc++.h>
using namespace std;
#define N 300001
#define pb push_back
#define mp make_pair
#define all(v) v.begin(),v.end()
#define F first
#define S second
#define ll long long
#define pii pair <int ,int >
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define RFOR(i,a,b) for(int i=b;i>=a;i--)
#define si(x) scanf("%d",&x)
#define sl(x) scanf("%lld",&x)
#define boost ios::sync_with_stdio(false);cin.tie(0)
#define SET(arr,val) memset(arr,val,sizeof arr)
const ll inf=1e15,mod=1e8;
int dsu[N],dia[N];
std::vector<int > g[N];
int Getpar(int a)
{
    if(dsu[a]==a)
        return a;
    return dsu[a]=Getpar(dsu[a]);
}
void merge(int a,int b)
{
    a=Getpar(a);
    b=Getpar(b);
    if(a==b)
        return ;
    int d=max(max(dia[a],dia[b]),(dia[a]+1)/2+(dia[b]+1)/2+1);
    dsu[a]=dsu[b];
    dia[b]=d;
}
pii dfs(int node,int d,int par)
{
    pii u=mp(d,node);
    for(auto it:g[node])
    {
        if(par==it)
            continue;
        u=max(u,dfs(it,d+1,node));
    }
    return u;
}
int fun(int a)
{
    if(dia[a]!=-1)
        return dia[a];
    pii x= dfs(Getpar(a),0,Getpar(a));
    dia[a]=dfs(x.S,0,x.S).F;
    return dia[a];
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m,q;
    si(n),si(m),si(q);
    for(int i=1;i<=n;i++)
        dsu[i]=i;
    SET(dia,-1);
    for(int i=0;i<m;i++)
    {
        int a,b;
        si(a),si(b);
        g[a].pb(b);
        g[b].pb(a);
        merge(a,b);
    }
    for(int i=1;i<=n;i++)
    {
        dia[i]=fun(Getpar(i));
    }
    while(q--)
    {
        int c;
        si(c);
        if(c==1)
        {
            int x;
            si(x);
            cout<<dia[Getpar(x)]<<endl;
        }
        else
        {
            int a,b;
            si(a),si(b);
            merge(a,b);
        }
    }
    return 0;
}


//Siddharth Yadav
#include <bits/stdc++.h>
using namespace std;
#define N 300001
#define pb push_back
#define mp make_pair
#define all(v) v.begin(),v.end()
#define F first
#define S second
#define ll long long
#define pii pair <int ,int >
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define RFOR(i,a,b) for(int i=b;i>=a;i--)
#define si(x) scanf("%d",&x)
#define sl(x) scanf("%lld",&x)
#define boost ios::sync_with_stdio(false);cin.tie(0)
#define SET(arr,val) memset(arr,val,sizeof arr)
const ll inf=1e15,mod=1e8;
int dsu[N],dia[N];
std::vector<int > g[N];
int Getpar(int a)
{
    if(dsu[a]==a)
        return a;
    return dsu[a]=Getpar(dsu[a]);
}
void merge(int x,int y)
{
    int a=Getpar(x);
    int b=Getpar(y);
    if(a==b)
        return ;
    int d=max(max(dia[a],dia[b]),(dia[a]+1)/2+(dia[b]+1)/2+1);
    dsu[a]=dsu[b];
    dia[Getpar(b)]=d;
}
pii dfs(int node,int d,int par)
{
    pii u=mp(d,node);
    for(auto it:g[node])
    {
        if(par==it)
            continue;
        u=max(u,dfs(it,d+1,node));
    }
    return u;
}
int fun(int a)
{
    if(dia[a]!=-1)
        return dia[a];
    pii x= dfs(Getpar(a),0,Getpar(a));
    dia[a]=dfs(x.S,0,x.S).F;
    return dia[a];
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m,q;
    si(n),si(m),si(q);
    for(int i=1;i<=n;i++)
        dsu[i]=i;
    SET(dia,-1);
    for(int i=0;i<m;i++)
    {
        int a,b;
        si(a),si(b);
        g[a].pb(b);
        g[b].pb(a);
        dsu[Getpar(b)]==Getpar(a);
    }
    for(int i=1;i<=n;i++)
    {
        dia[i]=fun(Getpar(i));
    }
    while(q--)
    {
        int c;
        si(c);
        if(c==1)
        {
            int x;
            si(x);
            cout<<dia[Getpar(x)]<<endl;
        }
        else
        {
            int a,b;
            si(a),si(b);
            merge(a,b);
        }
    }
    return 0;
}


//Siddharth Yadav
#include <bits/stdc++.h>
using namespace std;
#define N 300001
#define pb push_back
#define mp make_pair
#define all(v) v.begin(),v.end()
#define F first
#define S second
#define ll long long
#define pii pair <int ,int >
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define RFOR(i,a,b) for(int i=b;i>=a;i--)
#define si(x) scanf("%d",&x)
#define sl(x) scanf("%lld",&x)
#define boost ios::sync_with_stdio(false);cin.tie(0)
#define SET(arr,val) memset(arr,val,sizeof arr)
const ll inf=1e15,mod=1e8;
int dsu[N],dia[N];
std::vector<int > g[N];
int Getpar(int a)
{
    if(dsu[a]==a)
        return a;
    return dsu[a]=Getpar(dsu[a]);
}
void merge(int x,int y)
{
    int a=Getpar(x);
    int b=Getpar(y);
    if(a==b)
        return ;
    int d=max(max(dia[a],dia[b]),(dia[a]+1)/2+(dia[b]+1)/2+1);
    dsu[a]=dsu[b];
    dia[Getpar(b)]=d;
}
pii dfs(int node,int d,int par)
{
    pii u=mp(d,node);
    for(auto it:g[node])
    {
        if(par==it)
            continue;
        u=max(u,dfs(it,d+1,node));
    }
    return u;
}
int fun(int a)
{
    if(dia[a]!=-1)
        return dia[a];
    pii x= dfs(Getpar(a),0,Getpar(a));
    dia[a]=dfs(x.S,0,x.S).F;
    return dia[a];
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m,q;
    si(n),si(m),si(q);
    for(int i=1;i<=n;i++)
        dsu[i]=i;
    SET(dia,-1);
    for(int i=0;i<m;i++)
    {
        int a,b;
        si(a),si(b);
        g[a].pb(b);
        g[b].pb(a);
        dsu[Getpar(b)]=Getpar(a);
    }
    for(int i=1;i<=n;i++)
    {
        dia[i]=fun(Getpar(i));
    }
    while(q--)
    {
        int c;
        si(c);
        if(c==1)
        {
            int x;
            si(x);
            cout<<dia[Getpar(x)]<<endl;
        }
        else
        {
            int a,b;
            si(a),si(b);
            merge(a,b);
        }
    }
    return 0;
}


#include <bits/stdc++.h>
#define mod 1000000007
#define INF 1000000000
#define SZ 100009
#define ull unsigned long long
#define ll long long int
#define ld long double
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define ppb pop_back
#define ppf pop_front
#define all(v) ((v).begin()), ((v).end())
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define db(...) ZZ(#__VA_ARGS__, __VA_ARGS__)
#define dbvv(v) cout << "Printing "#v << " --> \n"; for(ll i=0;i<v.size();i++) {for(ll j=0;j<v[i].size();j++) cout << v[i][j] << " "; cout << "\n";}
#define dbv(st) cout << "Printing "#st << " --> \n"; for(auto i=st.begin();i!=st.end();i++) cout << *i << " "; cout << "\n";
#define dbvp(st) cout << "Printing "#st << " --> \n"; for(auto i=st.begin();i!=st.end();i++) cout << i->first << " " << i->second << "\n"; cout << "\n";
#define dbmp(mp) cout << "Printing "#mp << " --> \n"; for(auto i=mp.begin();i!=mp.end();i++) cout << #mp"[" << i->first << "]"<< " = " << i->second << "\n";
#define dbar(ar,st,en) cout << "Printing "#ar << " --> \n"; for(auto it=st;it!=en;it++) cout << *it << " "; cout << "\n";
#define dbmar(ar,rowz,colz) cout << "Printing "#ar << " --> \n"; for(auto i=0;i<rowz;i++) {for(auto j=0;j<colz;j++) cout << ar[i][j] << " "; cout << "\n";}
template <typename Arg1>void ZZ(const char* name, Arg1&& arg1){std::cout << name << " = " << arg1 << std::endl;}
template <typename Arg1, typename... Args>void ZZ(const char* names, Arg1&& arg1, Args&&... args)
{
    const char* comma = strchr(names + 1, ',');
    std::cout.write(names, comma - names) << " = " << arg1;
    ZZ(comma, args...);
}
using namespace std;
/*
##########################
## Author: Viral Mehta  ##
## College: BITS Pilani ##
##########################
*/
ll to_ll(string &s)
{
	ll i,ret=0,p=1;
	for(i=(ll)s.length()-1;i>=0;i--) ret+=(s[i]-'0')*p, p*=10LL;
	return ret;
}
ll gcd(ll x,ll y)
{
	if(y==0) return x;
	return gcd(y,x%y);
}
ll pwr(ll base,ll expo,ll m)
{
	if(base==0) return 0LL;
	if(expo==0) return (1LL%m);
	if((expo&1)==0) {ll temp=pwr(base,expo>>1,m); return (temp*temp)%m;}
	return ((base%m)*pwr(base,expo-1,m))%mod;
}
/*-----------------------------------------------------------------------------------------------------------------------------------------*/
ll n,m,q;
vector<ll> adj[SZ],parent,diameter,vis,sz;
void max_dfs(ll node,ll p,ll dis,ll *max_dis,ll *max_dis_node)
{
	vis[node]=1;
	if(*max_dis<dis) {*max_dis=dis; *max_dis_node=node;}
	ll i;
	for(i=0;i<adj[node].size();i++)
	{
		ll nxt=adj[node][i];
		if(p==nxt) continue;
		max_dfs(nxt,node,dis+1,max_dis,max_dis_node);
	}
}
ll find_diameter(ll node)
{
	//db(node);
	ll max_dis=0,u=0,v=0;
	max_dfs(node,-1,0,&max_dis,&u);
	//db("1",u,v,max_dis);
	max_dis=0;
	max_dfs(u,-1,0,&max_dis,&v);
	//db("2",u,v,max_dis);
	return max_dis;
}
ll fnd(ll x)
{
	while(parent[x]!=x) x=parent[x];
	return x;
}
void unite(ll x,ll y,ll mode)
{
	ll px=fnd(x);
	ll py=fnd(y);
	if(px==py) return;
	if(sz[px]>sz[py])
	{
		parent[py]=px, sz[px]+=sz[py];
		if(mode==2) diameter[px]=max(max(diameter[px],diameter[py]),1LL+(ll)ceil(diameter[px]/2.0)+(ll)ceil(diameter[py]/2.0));
	}
	else
	{
		parent[px]=py, sz[py]+=sz[px];
		if(mode==2) diameter[py]=max(max(diameter[px],diameter[py]),1LL+(ll)ceil(diameter[px]/2.0)+(ll)ceil(diameter[py]/2.0));
	}
}
int main()
{
	ios;
	ll i,j,type,x,y;
	cin>>n>>m>>q; parent.resize(n+1); diameter.resize(n+1); vis.resize(n+1); sz.resize(n+1,1);
	for(i=1;i<=n;i++) parent[i]=i;
	for(i=0;i<m;i++)
	{
		cin>>x>>y;
		adj[x].pb(y);
		adj[y].pb(x);
		unite(x,y,1);
	}
	//dbv(parent);
	for(i=1;i<=n;i++) if(vis[i]==0) diameter[parent[i]]=find_diameter(parent[i]);
	//dbv(diameter);
	while(q--)
	{
		cin>>type>>x;
		if(type==1) cout << diameter[parent[x]] << "\n";
		else cin>>y, unite(x,y,2);
		//dbv(parent);dbv(diameter);dbv(sz);db("-----------------------------");
	}
	return 0;
}


#include <bits/stdc++.h>
#define mod 1000000007
#define INF 1000000000
#define SZ 300009
#define ull unsigned long long
#define ll long long int
#define ld long double
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define ppb pop_back
#define ppf pop_front
#define all(v) ((v).begin()), ((v).end())
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define db(...) ZZ(#__VA_ARGS__, __VA_ARGS__)
#define dbvv(v) cout << "Printing "#v << " --> \n"; for(ll i=0;i<v.size();i++) {for(ll j=0;j<v[i].size();j++) cout << v[i][j] << " "; cout << "\n";}
#define dbv(st) cout << "Printing "#st << " --> \n"; for(auto i=st.begin();i!=st.end();i++) cout << *i << " "; cout << "\n";
#define dbvp(st) cout << "Printing "#st << " --> \n"; for(auto i=st.begin();i!=st.end();i++) cout << i->first << " " << i->second << "\n"; cout << "\n";
#define dbmp(mp) cout << "Printing "#mp << " --> \n"; for(auto i=mp.begin();i!=mp.end();i++) cout << #mp"[" << i->first << "]"<< " = " << i->second << "\n";
#define dbar(ar,st,en) cout << "Printing "#ar << " --> \n"; for(auto it=st;it!=en;it++) cout << *it << " "; cout << "\n";
#define dbmar(ar,rowz,colz) cout << "Printing "#ar << " --> \n"; for(auto i=0;i<rowz;i++) {for(auto j=0;j<colz;j++) cout << ar[i][j] << " "; cout << "\n";}
template <typename Arg1>void ZZ(const char* name, Arg1&& arg1){std::cout << name << " = " << arg1 << std::endl;}
template <typename Arg1, typename... Args>void ZZ(const char* names, Arg1&& arg1, Args&&... args)
{
    const char* comma = strchr(names + 1, ',');
    std::cout.write(names, comma - names) << " = " << arg1;
    ZZ(comma, args...);
}
using namespace std;
/*
##########################
## Author: Viral Mehta  ##
## College: BITS Pilani ##
##########################
*/
ll to_ll(string &s)
{
	ll i,ret=0,p=1;
	for(i=(ll)s.length()-1;i>=0;i--) ret+=(s[i]-'0')*p, p*=10LL;
	return ret;
}
ll gcd(ll x,ll y)
{
	if(y==0) return x;
	return gcd(y,x%y);
}
ll pwr(ll base,ll expo,ll m)
{
	if(base==0) return 0LL;
	if(expo==0) return (1LL%m);
	if((expo&1)==0) {ll temp=pwr(base,expo>>1,m); return (temp*temp)%m;}
	return ((base%m)*pwr(base,expo-1,m))%mod;
}
/*-----------------------------------------------------------------------------------------------------------------------------------------*/
ll n,m,q;
vector<ll> adj[SZ],parent,diameter,vis,sz;
void max_dfs(ll node,ll p,ll dis,ll *max_dis,ll *max_dis_node)
{
	vis[node]=1;
	if(*max_dis<dis) {*max_dis=dis; *max_dis_node=node;}
	ll i;
	for(i=0;i<adj[node].size();i++)
	{
		ll nxt=adj[node][i];
		if(p==nxt) continue;
		max_dfs(nxt,node,dis+1,max_dis,max_dis_node);
	}
}
ll find_diameter(ll node)
{
	//db(node);
	ll max_dis=0,u=0,v=0;
	max_dfs(node,-1,0,&max_dis,&u);
	//db("1",u,v,max_dis);
	max_dis=0;
	max_dfs(u,-1,0,&max_dis,&v);
	//db("2",u,v,max_dis);
	return max_dis;
}
ll fnd(ll x)
{
	while(parent[x]!=x) x=parent[x];
	return x;
}
void unite(ll x,ll y,ll mode)
{
	ll px=fnd(x);
	ll py=fnd(y);
	if(px==py) return;
	if(sz[px]>sz[py])
	{
		if(mode==2) diameter[px]=max(max(diameter[px],diameter[py]),1LL+((1+diameter[py])/2)+((1+diameter[px])/2));
		parent[py]=px, sz[px]+=sz[py];
	}
	else
	{
		if(mode==2) diameter[py]=max(max(diameter[px],diameter[py]),1LL+(1+diameter[py])/2+(1+diameter[px])/2);
		parent[px]=py, sz[py]+=sz[px];
	}
}
int main()
{
	ios;
	ll i,j,type,x,y;
	cin>>n>>m>>q; parent.resize(n+1); diameter.resize(n+1); vis.resize(n+1); sz.resize(n+1,1);
	for(i=1;i<=n;i++) parent[i]=i;
	for(i=0;i<m;i++)
	{
		cin>>x>>y;
		adj[x].pb(y);
		adj[y].pb(x);
		unite(x,y,1);
	}
	//dbv(parent);
	for(i=1;i<=n;i++) if(vis[i]==0) diameter[fnd(i)]=find_diameter(fnd(i));
	//dbv(diameter);
	while(q--)
	{
		cin>>type>>x;
		if(type==1) cout << diameter[fnd(x)] << "\n";
		else cin>>y, unite(x,y,2);
		//dbv(parent);dbv(diameter);dbv(sz);db("-----------------------------");}
	}
	return 0;
}
/*
10 1 6
1 2
2 2 5
2 10 9
2 4 8
2 1 10
2 2 4
1 10
*/


#include <bits/stdc++.h>
#define mod 1000000007
#define INF 1000000000
#define SZ 100009
#define ull unsigned long long
#define ll long long int
#define ld long double
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define ppb pop_back
#define ppf pop_front
#define all(v) ((v).begin()), ((v).end())
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define db(...) ZZ(#__VA_ARGS__, __VA_ARGS__)
#define dbvv(v) cout << "Printing "#v << " --> \n"; for(ll i=0;i<v.size();i++) {for(ll j=0;j<v[i].size();j++) cout << v[i][j] << " "; cout << "\n";}
#define dbv(st) cout << "Printing "#st << " --> \n"; for(auto i=st.begin();i!=st.end();i++) cout << *i << " "; cout << "\n";
#define dbvp(st) cout << "Printing "#st << " --> \n"; for(auto i=st.begin();i!=st.end();i++) cout << i->first << " " << i->second << "\n"; cout << "\n";
#define dbmp(mp) cout << "Printing "#mp << " --> \n"; for(auto i=mp.begin();i!=mp.end();i++) cout << #mp"[" << i->first << "]"<< " = " << i->second << "\n";
#define dbar(ar,st,en) cout << "Printing "#ar << " --> \n"; for(auto it=st;it!=en;it++) cout << *it << " "; cout << "\n";
#define dbmar(ar,rowz,colz) cout << "Printing "#ar << " --> \n"; for(auto i=0;i<rowz;i++) {for(auto j=0;j<colz;j++) cout << ar[i][j] << " "; cout << "\n";}
template <typename Arg1>void ZZ(const char* name, Arg1&& arg1){std::cout << name << " = " << arg1 << std::endl;}
template <typename Arg1, typename... Args>void ZZ(const char* names, Arg1&& arg1, Args&&... args)
{
    const char* comma = strchr(names + 1, ',');
    std::cout.write(names, comma - names) << " = " << arg1;
    ZZ(comma, args...);
}
using namespace std;
/*
##########################
## Author: Viral Mehta  ##
## College: BITS Pilani ##
##########################
*/
ll to_ll(string &s)
{
	ll i,ret=0,p=1;
	for(i=(ll)s.length()-1;i>=0;i--) ret+=(s[i]-'0')*p, p*=10LL;
	return ret;
}
ll gcd(ll x,ll y)
{
	if(y==0) return x;
	return gcd(y,x%y);
}
ll pwr(ll base,ll expo,ll m)
{
	if(base==0) return 0LL;
	if(expo==0) return (1LL%m);
	if((expo&1)==0) {ll temp=pwr(base,expo>>1,m); return (temp*temp)%m;}
	return ((base%m)*pwr(base,expo-1,m))%mod;
}
/*-----------------------------------------------------------------------------------------------------------------------------------------*/
ll n,m,q;
vector<ll> adj[SZ],parent,diameter,vis,sz;
void max_dfs(ll node,ll p,ll dis,ll *max_dis,ll *max_dis_node)
{
	vis[node]=1;
	if(*max_dis<dis) {*max_dis=dis; *max_dis_node=node;}
	ll i;
	for(i=0;i<adj[node].size();i++)
	{
		ll nxt=adj[node][i];
		if(p==nxt) continue;
		max_dfs(nxt,node,dis+1,max_dis,max_dis_node);
	}
}
ll find_diameter(ll node)
{
	//db(node);
	ll max_dis=0,u=0,v=0;
	max_dfs(node,-1,0,&max_dis,&u);
	//db("1",u,v,max_dis);
	max_dis=0;
	max_dfs(u,-1,0,&max_dis,&v);
	//db("2",u,v,max_dis);
	return max_dis;
}
ll fnd(ll x)
{
	while(parent[x]!=x) x=parent[x];
	return x;
}
void unite(ll x,ll y,ll mode)
{
	ll px=fnd(x);
	ll py=fnd(y);
	if(px==py) return;
	if(sz[px]>sz[py])
	{
		if(mode==2) diameter[px]=max(max(diameter[px],diameter[py]),1LL+((1+diameter[py])/2)+((1+diameter[px])/2));
		parent[py]=px, sz[px]+=sz[py];
	}
	else
	{
		if(mode==2) diameter[py]=max(max(diameter[px],diameter[py]),1LL+(1+diameter[py])/2+(1+diameter[px])/2);
		parent[px]=py, sz[py]+=sz[px];
	}
}
int main()
{
	ios;
	ll i,j,type,x,y;
	cin>>n>>m>>q; parent.resize(n+1); diameter.resize(n+1); vis.resize(n+1); sz.resize(n+1,1);
	for(i=1;i<=n;i++) parent[i]=i;
	for(i=0;i<m;i++)
	{
		cin>>x>>y;
		adj[x].pb(y);
		adj[y].pb(x);
		unite(x,y,1);
	}
	//dbv(parent);
	for(i=1;i<=n;i++) if(vis[i]==0) diameter[fnd(i)]=find_diameter(fnd(i));
	//dbv(diameter);
	while(q--)
	{
		cin>>type>>x;
		if(type==1) cout << diameter[fnd(x)] << "\n";
		else cin>>y, unite(x,y,2);
		//dbv(parent);dbv(diameter);dbv(sz);db("-----------------------------");}
	}
	return 0;
}
/*
10 1 6
1 2
2 2 5
2 10 9
2 4 8
2 1 10
2 2 4
1 10
*/


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

template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template <typename T>
using dijkstra = priority_queue<T, vector<T>, greater<T>>;

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define fbo find_by_order  // k th index
#define ook order_of_key   // strictly smaller than k
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define max_ull 18446744073709551615
#define max_ll 9223372036854775807
#define lead_zero(x) __builtin_clzll(x)
#define trail_zero(x) __builtin_ctzll(x)
#define total_1s(x) __builtin_popcountll(x)
#define first_1(x) __builtin_ffsll(x)
#define log2_(x) __builtin_clz(1) - __builtin_clz(x)
#define isLeap(x) ((x % 400 == 0) || (x % 100 ? x % 4 == 0 : false))
#define QUERY           \
    int test;           \
    scanf("%d", &test); \
    for (int _T = 1; _T <= test; _T++)
#define FAST ios_base::sync_with_stdio(0), cin.tie(0)
#define all(v) v.begin(), v.end()
#define reunique(v) v.resize(std::unique(all(v)) - v.begin())
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pul pair<ull, ull>
#define ff first
#define ss second
#define MERGE(v1, v2, v) merge(all(v1), all(v2), back_inserter(v))
#define MP make_pair
#define EB emplace_back
#define read freopen("input.txt", "r", stdin)
#define write freopen("output.txt", "w", stdout)
#define in_range(v, r, l) upper_bound(all(v), r) - lower_bound(all(v), l)
#define LCM(a, b) (a / __gcd(a, b)) * b;

ll rdn(int y, int m, int d) {
    /* Rata Die day one is 0001-01-01 */
    if (m < 3)
        y--, m += 12;
    return 365 * y + y / 4 - y / 100 + y / 400 + (153 * m - 457) / 5 + d - 306;
}
/* Direction arrays */
/*int dx[] = {1,-1,0,0}, dy[] = {0,0,1,-1};                             */  // 4Direction
/*int dx[] = {1,-1,0,0,1,1,-1,-1}, dy[] = {0,0,1,-1,1,-1,1,-1};         */  // 8Direction
/* int dx[] = {1,-1,1,-1,2,2,-2,-2} , dy[] = {2,2,-2,-2,1,-1,1,-1};     */  // KnightDirection
/* int dx[] = {2,-2,1,1,-1,-1} , dy[] = {0,0,1,-1,1,-1};                */  // HexagonalDirection
/* int day[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; */

const int N = 3e5+9;
vector<int>v[N];
int visited[N];
int dist[N];
int comp[N];
stack<int>intree;
int maxdist[N];
int bfs(int x,int c){
    queue<int>q;
    q.push(x);
    visited[x]=1;
    dist[x]=0;
    int maxi = -1;
    int node = -1;
    while (!q.empty())
    {
        int t = q.front();
        intree.push(t);
        comp[t]=c;
        q.pop();
        if(maxi<dist[t]){
            maxi = dist[t];
            node = t;
        }
        for(int i=0;i<v[t].size();i++){
            int p = v[t][i];
            if(visited[p])continue;
            visited[p] = 1;
            dist[p] = dist[t]+1;
            q.push(p);
        }
    }
    return node;
}
int find(int x){
    while (comp[x]!=x)
    {
        comp[x] = comp[comp[x]];
        x=comp[x];
    }
    return x;
}

void UNION(int x,int y){
    x = find(x);
    y = find(y);
    if(x==y)return;
    if(maxdist[x]<maxdist[y])swap(x,y);
    maxdist[x] = max(maxdist[x],maxdist[x]/2+(maxdist[x]%2?1:0)+1+maxdist[y]);
    comp[y] = x;
    return;
}
int main() {
    int n,m,q;
    scanf("%d %d %d",&n,&m,&q);
    int a,b;
    for(int i=0;i<m;i++){
        scanf("%d %d",&a,&b);
        v[a].EB(b);
        v[b].EB(a);
    }
    //find perimeter of every tree
    for(int i=1;i<=n;i++){
        if(visited[i])continue;
        int node1 = bfs(i,i);
        while (intree.empty()==false)
        {
            visited[intree.top()]=0;
            intree.pop();
        }

        int node2 = bfs(node1,node1);
        maxdist[node1] = dist[node2];
        while (intree.empty() == false) {
            intree.pop();
        }
    }
    int type;
    while (q--)
    {
        scanf("%d %d",&type,&a);
        if(type==2){
            scanf("%d",&b);
            UNION(a,b);
        }
        else{
            a = find(a);
            printf("%d\n",maxdist[a]);
        }
    }
}


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

template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template <typename T>
using dijkstra = priority_queue<T, vector<T>, greater<T>>;

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define fbo find_by_order  // k th index
#define ook order_of_key   // strictly smaller than k
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define max_ull 18446744073709551615
#define max_ll 9223372036854775807
#define lead_zero(x) __builtin_clzll(x)
#define trail_zero(x) __builtin_ctzll(x)
#define total_1s(x) __builtin_popcountll(x)
#define first_1(x) __builtin_ffsll(x)
#define log2_(x) __builtin_clz(1) - __builtin_clz(x)
#define isLeap(x) ((x % 400 == 0) || (x % 100 ? x % 4 == 0 : false))
#define QUERY           \
    int test;           \
    scanf("%d", &test); \
    for (int _T = 1; _T <= test; _T++)
#define FAST ios_base::sync_with_stdio(0), cin.tie(0)
#define all(v) v.begin(), v.end()
#define reunique(v) v.resize(std::unique(all(v)) - v.begin())
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pul pair<ull, ull>
#define ff first
#define ss second
#define MERGE(v1, v2, v) merge(all(v1), all(v2), back_inserter(v))
#define MP make_pair
#define EB emplace_back
#define read freopen("input.txt", "r", stdin)
#define write freopen("output.txt", "w", stdout)
#define in_range(v, r, l) upper_bound(all(v), r) - lower_bound(all(v), l)
#define LCM(a, b) (a / __gcd(a, b)) * b;

ll rdn(int y, int m, int d) {
    /* Rata Die day one is 0001-01-01 */
    if (m < 3)
        y--, m += 12;
    return 365 * y + y / 4 - y / 100 + y / 400 + (153 * m - 457) / 5 + d - 306;
}
/* Direction arrays */
/*int dx[] = {1,-1,0,0}, dy[] = {0,0,1,-1};                             */  // 4Direction
/*int dx[] = {1,-1,0,0,1,1,-1,-1}, dy[] = {0,0,1,-1,1,-1,1,-1};         */  // 8Direction
/* int dx[] = {1,-1,1,-1,2,2,-2,-2} , dy[] = {2,2,-2,-2,1,-1,1,-1};     */  // KnightDirection
/* int dx[] = {2,-2,1,1,-1,-1} , dy[] = {0,0,1,-1,1,-1};                */  // HexagonalDirection
/* int day[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; */

const int N = 3e5+9;
vector<int>v[N];
int visited[N];
int dist[N];
int comp[N];
stack<int>intree;
int maxdist[N];
int bfs(int x,int c){
    queue<int>q;
    q.push(x);
    visited[x]=1;
    dist[x]=0;
    int maxi = -1;
    int node = -1;
    while (!q.empty())
    {
        int t = q.front();
        intree.push(t);
        comp[t]=c;
        q.pop();
        if(maxi<dist[t]){
            maxi = dist[t];
            node = t;
        }
        for(int i=0;i<v[t].size();i++){
            int p = v[t][i];
            if(visited[p])continue;
            visited[p] = 1;
            dist[p] = dist[t]+1;
            q.push(p);
        }
    }
    return node;
}
int find(int x){
    while (comp[x]!=x)
    {
        comp[x] = comp[comp[x]];
        x=comp[x];
    }
    return x;
}

void UNION(int x,int y){
    x = find(x);
    y = find(y);
    if(x==y)return;
    if(maxdist[x]<maxdist[y])swap(x,y);
    maxdist[x] = max(maxdist[x],maxdist[x]/2+(maxdist[x]%2?1:0)+1+(maxdist[y]/2)+(maxdist[y]%2?1:0));
    comp[y] = x;
    return;
}
int main() {
    int n,m,q;
    scanf("%d %d %d",&n,&m,&q);
    int a,b;
    for(int i=0;i<m;i++){
        scanf("%d %d",&a,&b);
        v[a].EB(b);
        v[b].EB(a);
    }
    //find perimeter of every tree
    for(int i=1;i<=n;i++){
        if(visited[i])continue;
        int node1 = bfs(i,i);
        while (intree.empty()==false)
        {
            visited[intree.top()]=0;
            intree.pop();
        }

        int node2 = bfs(node1,node1);
        maxdist[node1] = dist[node2];
        while (intree.empty() == false) {
            intree.pop();
        }
    }
    int type;
    while (q--)
    {
        scanf("%d %d",&type,&a);
        if(type==2){
            scanf("%d",&b);
            UNION(a,b);
        }
        else{
            a = find(a);
            printf("%d\n",maxdist[a]);
        }
    }
}


#include <bits/stdc++.h>

using namespace std;

int diam[300005];
int p[300005];
int n,m,q,l,r,x,t,a,b;
int bb,mx(0);

vector<vector<int> > g(300005);
bool used1[300005];
bool used2[300005];
bool used3[300005];

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

void union_(int u,int v)
{
          u=find_(u);
          v=find_(v);
          if(rand()%2)
                    swap(u,v);
          if(u!=v)
          {
                    p[v]=u;
                    diam[u]=max(max(diam[v],diam[u]),(diam[u]+1)/2+(diam[v]+1)/2+1);
          }
}

void dfs1(int u,int d)
{
          used1[u]=1;
          if(mx<d)
          {
                    mx=d;
                    bb=u;
          }
          for(size_t i=0;i<g[u].size();i++)
          {
                    int to=g[u][i];
                    if(!used1[to])
                              dfs1(to,d+1);
          }
}

void dfs2(int u,int d)
{
          used2[u]=1;
          if(mx<d)
                    mx=d;
          for(size_t i=0;i<g[u].size();i++)
          {
                    int to=g[u][i];
                    if(!used2[to])
                              dfs2(to,d+1);
          }
}

void dfs3(int u)
{
          used3[u]=1;
          diam[u]=mx;
          for(size_t i=0;i<g[u].size();i++)
          {
                    int to=g[u][i];
                    if(!used3[to])
                              dfs3(to);
          }
}

void do_work()
{
          for(int i=0;i<n;i++)
          {
                    if(!used1[i])
                    {
                              mx=0;
                              bb=0;
                              dfs1(i,0);
                              mx=0;
                              dfs2(bb,0);
                              dfs3(i);
                    }
          }
}

int main()
{
          //freopen("INPUT.txt","r",stdin);
          scanf("%d %d %d",&n,&m,&q);
          for(int i=0;i<300005;i++)
                    p[i]=i;
          for(int i=0;i<m;i++)
          {
                    scanf("%d %d",&l,&r);
                    l--;
                    r--;
                    union_(l,r);
                    g[l].push_back(r);
                    g[r].push_back(l);
          }
          do_work();
          for(int i=0;i<q;i++)
          {
                    scanf("%d",&t);
                    if(t==1)
                    {
                              scanf("%d",&x);
                              x--;
                              printf("%d\n",diam[find_(x)]);
                    }
                    else
                    {
                              scanf("%d %d",&a,&b);
                              a--;
                              b--;
                              union_(a,b);
                    }
          }

}


#include <bits/stdc++.h>

using namespace std;

int diam[300005];
int p[300005];
int n,m,q,l,r,x,t,a,b;
int bb,mx(0);

vector<vector<int> > g(300005);
bool used1[300005];
bool used2[300005];
bool used3[300005];

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

void union_(int u,int v)
{
          u=find_(u);
          v=find_(v);
          if(rand()%2)
                    swap(u,v);
          if(u!=v)
          {
                    p[v]=u;
                    diam[u]=max(max(diam[v],diam[u]),(diam[u]+1)/2+(diam[v]+1)/2);
          }
}

void dfs1(int u,int d)
{
          used1[u]=1;
          if(mx<d)
          {
                    mx=d;
                    bb=u;
          }
          for(size_t i=0;i<g[u].size();i++)
          {
                    int to=g[u][i];
                    if(!used1[to])
                              dfs1(to,d+1);
          }
}

void dfs2(int u,int d)
{
          used2[u]=1;
          if(mx<d)
                    mx=d;
          for(size_t i=0;i<g[u].size();i++)
          {
                    int to=g[u][i];
                    if(!used2[to])
                              dfs2(to,d+1);
          }
}

void dfs3(int u)
{
          used3[u]=1;
          diam[u]=mx;
          for(size_t i=0;i<g[u].size();i++)
          {
                    int to=g[u][i];
                    if(!used3[to])
                              dfs3(to);
          }
}

void do_work()
{
          for(int i=0;i<300005;i++)
                    p[i]=i;
          for(int i=0;i<n;i++)
          {
                    if(!used1[i])
                    {
                              mx=0;
                              bb=0;
                              dfs1(i,0);
                              mx=0;
                              dfs2(bb,0);
                              dfs3(i);
                    }
          }
}

int main()
{
          //freopen("INPUT.txt","r",stdin);
          scanf("%d %d %d",&n,&m,&q);
          for(int i=0;i<m;i++)
          {
                    scanf("%d %d",&l,&r);
                    l--;
                    r--;
                    g[l].push_back(r);
                    g[r].push_back(l);
          }
          do_work();
          for(int i=0;i<q;i++)
          {
                    scanf("%d",&t);
                    if(t==1)
                    {
                              scanf("%d",&x);
                              x--;
                              printf("%d\n",diam[find_(x)]);
                    }
                    else
                    {
                              scanf("%d %d",&a,&b);
                              a--;
                              b--;
                              union_(a,b);
                    }
          }

}


#include <bits/stdc++.h>

using namespace std;

int diam[300005];
int p[300005];
int n,m,q,l,r,x,t,a,b;
int bb,mx(0);

vector<vector<int> > g(300005);
bool used1[300005];
bool used2[300005];
bool used3[300005];

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

void union_(int u,int v)
{
          u=find_(u);
          v=find_(v);
          if(rand()%2)
                    swap(u,v);
          if(u!=v)
          {
                    p[v]=u;
                    diam[u]=max(max(diam[v],diam[u]),(diam[u]+1)/2+(diam[v]+1)/2+1);
          }
}

void dfs1(int u,int d)
{
          used1[u]=1;
          if(mx<d)
          {
                    mx=d;
                    bb=u;
          }
          for(size_t i=0;i<g[u].size();i++)
          {
                    int to=g[u][i];
                    if(!used1[to])
                              dfs1(to,d+1);
          }
}

void dfs2(int u,int d)
{
          used2[u]=1;
          if(mx<d)
                    mx=d;
          for(size_t i=0;i<g[u].size();i++)
          {
                    int to=g[u][i];
                    if(!used2[to])
                              dfs2(to,d+1);
          }
}

void dfs3(int u)
{
          used3[u]=1;
          diam[u]=mx;
          for(size_t i=0;i<g[u].size();i++)
          {
                    int to=g[u][i];
                    if(!used3[to])
                              dfs3(to);
          }
}

void do_work()
{
          for(int i=0;i<300005;i++)
                    p[i]=i;
          for(int i=0;i<n;i++)
          {
                    if(!used1[i])
                    {
                              mx=0;
                              bb=0;
                              dfs1(i,0);
                              mx=0;
                              dfs2(bb,0);
                              dfs3(i);
                    }
          }
}

int main()
{
          scanf("%d %d %d",&n,&m,&q);
          for(int i=0;i<m;i++)
          {
                    scanf("%d %d",&l,&r);
                    l--;
                    r--;
                    g[l].push_back(r);
                    g[r].push_back(l);
          }
          do_work();
          for(int i=0;i<q;i++)
          {
                    scanf("%d",&t);
                    if(t==1)
                    {
                              scanf("%d",&x);
                              x--;
                              printf("%d\n",diam[find_(x)]);
                    }
                    else
                    {
                              scanf("%d %d",&a,&b);
                              a--;
                              b--;
                              union_(a,b);
                    }
          }

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;

public class Main {
	public static class Union_Set{
		int parent[];
		int score[];
		public Union_Set(int []parent,int[]score){
			this.parent=parent;
			this.score=score;
		}
		public int getScore(int node){
			return score[node];
		}
		public int findParent(int i){
			if(parent[i]==i)
				return i;
			else{
				int p=i;
				while(p!=parent[p])
					p=parent[p];
				parent[i]=p;
				return p;
			}
		}
		public void set_Union(int set1,int set2){
			int parent1=findParent(set1);
			int parent2=findParent(set2);
			if(set1+1==set2){

				if(parent2==set2)
					score[set2]=Math.max(score[set2], score[set1]+score[set2]);
				score[set2]=Math.max(score[set2], score[set1]+1);
				parent[parent2]=parent1;
				parent[set2]=parent1;
				score[parent1]=Math.max(Math.max(score[parent1], score[set2]),score[parent2]);
			}else{
				if(set1==set2+1){

					if(parent1==set1)
						score[set1]=Math.max(score[set1], score[set1]+score[set2]);
					score[set1]=Math.max(score[set1], score[set2]+1);
					parent[parent1]=parent2;
					parent[set1]=parent2;
					score[parent2]=Math.max(Math.max(score[parent2], score[set1]),score[parent1]);
				}else{

					if(score[parent1]>score[parent2])
						parent[parent2]=parent1;
					else
						if(score[parent1]<=score[parent2])
							parent[parent1]=parent2;
				}
			}

		}
	}
	public static void main(String args[]) throws NumberFormatException,IOException {

		Stdin in = new Stdin();
		PrintWriter out = new PrintWriter(System.out);
		int n=in.readInt();
		int m=in.readInt();
		int q=in.readInt();
		int []parent=new int[n];
		int score[]=new int[n];
		int a,b,type,x,y,p1,p2;
		for(int i=0;i<n;i++){
			parent[i]=i;
			score[i]=1;
		}
		Union_Set union=new Union_Set(parent,score);
		for(int i=0;i<m;i++){
			a=in.readInt()-1;
			b=in.readInt()-1;

			if(a!=b)
				union.set_Union(a,b);

		}
		for(int i=0;i<q;i++){
			type=in.readInt();
			if(type==1){
				x=in.readInt()-1;
				p1=union.findParent(x);
				out.println(union.getScore(p1));
			}else{
				x=in.readInt()-1;
				y=in.readInt()-1;
				if(x!=y){

						union.set_Union(x,y);
				}
			}
		}

		out.flush();
		out.close();

	}

	private static class Stdin {
		InputStreamReader read;
		BufferedReader br;

		StringTokenizer st = new StringTokenizer("");

		private Stdin() {
			read = new InputStreamReader(System.in);
			br = new BufferedReader(read);

		}

		private String readNext() throws IOException {

			while (!st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		private int readInt() throws IOException, NumberFormatException {

			return Integer.parseInt(readNext());

		}

		private long readLong() throws IOException, NumberFormatException {

			return Long.parseLong(readNext());

		}
	}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.StringTokenizer;

public class Main {
	public static class Union_Set {
		int parent[];
		int max_path[];

		public Union_Set(int[] parent, int max_path[]) {
			this.parent = parent;
			this.max_path = max_path;

		}

		public int getMaxPathById(int id) {

			return max_path[findParent(id)];
		}

		public int getMaxPathByParent(int parent) {
			return max_path[parent];
		}

		public int findParent(int i) {
			if (parent[i] == i)
				return i;
			else {
				int p = i;
				while (p != parent[p]){
					parent[p]=parent[parent[p]];
					p = parent[p];
				}
				parent[i] = p;
				return p;
			}
		}

		public void set_Union(int set1, int set2) {
			int parent1 = findParent(set1);
			int parent2 = findParent(set2);
			if (parent1 < parent2) {
				max_path[parent1] = max(max(max_path[parent1], max_path[parent2]),
						(max_path[parent1] + 1) / 2 + (max_path[parent2] + 1)/ 2 + 1);
				parent[parent2] = parent1;
			} else {
				if (parent1 > parent2) {
					max_path[parent2] = max(max(max_path[parent1], max_path[parent2]),
							(max_path[parent1] + 1) / 2+ (max_path[parent2] + 1) / 2 + 1);
					parent[parent1] = parent2;
				}

			}
		}

		public int max(int a, int b) {
			return a < b ? b : a;
		}
	}

	public static void depth(ArrayList<Integer> graph[], int[] parent,int[] max_path) {
		int end;
		int depth[] = new int[graph.length];
		boolean visited[] = new boolean[graph.length];
		int depth0[] = new int[graph.length];
		boolean visited0[] = new boolean[graph.length];
		LinkedList<Integer> queue = new LinkedList<Integer>();
		for (int i = 0; i < graph.length; i++) {
			if (!visited[i]&&!graph[i].isEmpty()) {
				end = bfs0(graph, parent, i,queue,depth0,visited0);
				if (end != i) {
					end = bfs(graph, depth, visited, end,queue);
					max_path[i] = depth[end];
				}else
					visited[i]=true;
			}
		}

	}

	public static int bfs0(ArrayList<Integer>[] graph, int[] parent, int start,LinkedList<Integer>queue,int depth[],boolean visited[]) {
		int v = -1;
		int max = 0;
		int cur;
		queue.add(start);
		visited[start]=true;
		while (!queue.isEmpty()) {
			cur = queue.pollFirst();
			for (int u : graph[cur]) {
				if (!visited[u]) {
					depth[u] = depth[cur] + 1;
					queue.add(u);
					visited[u]=true;
					if (depth[u] > max) {
						max = depth[u];
						v = u;
					}
					parent[u] = start;
				}
			}
		}
		if (v == -1)
			return start;
		return v;

	}

	public static int bfs(ArrayList<Integer>[] graph, int depth[],boolean visited[], int start,LinkedList<Integer>queue) {
		int v = -1;
		int max = 0;
		int cur;
		queue.add(start);
		visited[start]=true;
		while (!queue.isEmpty()) {
			cur = queue.pollFirst();
			for (int u : graph[cur]) {
				if (!visited[u]) {
					depth[u] = depth[cur] + 1;
					queue.add(u);
					visited[u]=true;
					if (depth[u] > max) {
						max = depth[u];
						v = u;
					}
				}

			}
		}
		return v;

	}

	public static void main(String args[]) throws NumberFormatException,
			IOException {

		Stdin in = new Stdin();
		PrintWriter out = new PrintWriter(System.out);
		int n = in.readInt();
		int m = in.readInt();
		int q = in.readInt();
		int[] parent = new int[n];
		int[] max_path = new int[n];
		ArrayList<Integer> graph[] = new ArrayList[n];
		for (int i = 0; i < graph.length; i++)
			graph[i] = new ArrayList<Integer>();
		int a, b, type, x, y, p;
		for (int i = 0; i < n; i++) {
			parent[i] = i;
		}

		for (int i = 0; i < m; i++) {
			a = in.readInt() - 1;
			b = in.readInt() - 1;
			if (a != b) {
				graph[a].add(b);
				graph[b].add(a);
			}

		}
		depth(graph, parent, max_path);
		Union_Set union = new Union_Set(parent, max_path);
		for (int i = 0; i < q; i++) {
			type = in.readInt();
			if (type == 1) {
				x = in.readInt() - 1;
				p = union.findParent(x);
				out.println(max_path[p]);
			} else {
				x = in.readInt() - 1;
				y = in.readInt() - 1;
				if (x != y) {
					union.set_Union(x, y);
				}
			}
		}

		out.flush();
		out.close();

	}

	private static class Stdin {
		InputStreamReader read;
		BufferedReader br;

		StringTokenizer st = new StringTokenizer("");

		private Stdin() {
			read = new InputStreamReader(System.in);
			br = new BufferedReader(read);

		}

		private String readNext() throws IOException {

			while (!st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		private int readInt() throws IOException, NumberFormatException {

			return Integer.parseInt(readNext());

		}

		private long readLong() throws IOException, NumberFormatException {

			return Long.parseLong(readNext());

		}
	}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.StringTokenizer;

public class Main{
	public static class Union_Set {
		int parent[];
		int max_path[];

		public Union_Set(int[] parent, int max_path[]) {
			this.parent = parent;
			this.max_path = max_path;

		}

		public int getMaxPathById(int id) {

			return max_path[findParent(id)];
		}

		public int getMaxPathByParent(int parent) {
			return max_path[parent];
		}

		public int findParent(int i) {
			if (parent[i] == i)
				return i;
			else {
				int p = i;
				while (p != parent[p]){
					parent[p]=parent[parent[p]];
					p = parent[p];
				}
				parent[i] = p;
				return p;
			}
		}

		public void set_Union(int set1, int set2) {
			int parent1 = findParent(set1);
			int parent2 = findParent(set2);
			if (parent1 < parent2) {
				max_path[parent1] = max(max(max_path[parent1], max_path[parent2]),
						(max_path[parent1] + 1) / 2 + (max_path[parent2] + 1)/ 2 + 1);
				parent[parent2] = parent1;
			} else {
				if (parent1 > parent2) {
					max_path[parent2] = max(max(max_path[parent1], max_path[parent2]),
							(max_path[parent1] + 1) / 2+ (max_path[parent2] + 1) / 2 + 1);
					parent[parent1] = parent2;
				}

			}
		}

		public int max(int a, int b) {
			return a < b ? b : a;
		}
	}

	public static void depth(ArrayList<Integer> graph[], int[] parent,int[] max_path) {
		int end;
		int depth[] = new int[graph.length];
		boolean visited[] = new boolean[graph.length];
		LinkedList<Integer> queue = new LinkedList<Integer>();
		for (int i = 0; i < graph.length; i++) {
			if (!visited[i]&&!graph[i].isEmpty()) {
				end = bfs0(graph, parent, i,queue);
				if (end != i) {
					end = bfs(graph, depth, visited, end,queue);
					max_path[i] = depth[end];
				}else
					visited[i]=true;
			}
		}

	}

	public static int bfs0(ArrayList<Integer>[] graph, int[] parent, int start,LinkedList<Integer>queue) {
		int v = -1;
		int max = 0;
		int cur;
		boolean visited[] = new boolean[graph.length];
		int depth[] = new int[graph.length];
		queue.add(start);
		visited[start]=true;
		while (!queue.isEmpty()) {
			cur = queue.pollFirst();
			for (int u : graph[cur]) {
				if (!visited[u]) {
					depth[u] = depth[cur] + 1;
					queue.add(u);
					visited[u]=true;
					if (depth[u] > max) {
						max = depth[u];
						v = u;
					}
					parent[u] = start;
				}
			}
		}
		if (v == -1)
			return start;
		return v;

	}

	public static int bfs(ArrayList<Integer>[] graph, int depth[],boolean visited[], int start,LinkedList<Integer>queue) {
		int v = -1;
		int max = 0;
		int cur;
		queue.add(start);
		visited[start]=true;
		while (!queue.isEmpty()) {
			cur = queue.pollFirst();
			for (int u : graph[cur]) {
				if (!visited[u]) {
					depth[u] = depth[cur] + 1;
					queue.add(u);
					visited[u]=true;
					if (depth[u] > max) {
						max = depth[u];
						v = u;
					}
				}

			}
		}
		return v;

	}

	public static void main(String args[]) throws NumberFormatException,
			IOException {

		Stdin in = new Stdin();
		PrintWriter out = new PrintWriter(System.out);
		int n = in.readInt();
		int m = in.readInt();
		int q = in.readInt();
		int[] parent = new int[n];
		int[] max_path = new int[n];
		ArrayList<Integer> graph[] = new ArrayList[n];
		for (int i = 0; i < graph.length; i++)
			graph[i] = new ArrayList<Integer>();
		int a, b, type, x, y, p;
		for (int i = 0; i < n; i++) {
			parent[i] = i;
		}

		for (int i = 0; i < m; i++) {
			a = in.readInt() - 1;
			b = in.readInt() - 1;
			if (a != b) {
				graph[a].add(b);
				graph[b].add(a);
			}

		}
		depth(graph, parent, max_path);
		Union_Set union = new Union_Set(parent, max_path);
		for (int i = 0; i < q; i++) {
			type = in.readInt();
			if (type == 1) {
				x = in.readInt() - 1;
				p = union.findParent(x);
				out.println(union.getMaxPathByParent(p));
			} else {
				x = in.readInt() - 1;
				y = in.readInt() - 1;
				if (x != y) {
					union.set_Union(x, y);
				}
			}
		}

		out.flush();
		out.close();

	}

	private static class Stdin {
		InputStreamReader read;
		BufferedReader br;

		StringTokenizer st = new StringTokenizer("");

		private Stdin() {
			read = new InputStreamReader(System.in);
			br = new BufferedReader(read);

		}

		private String readNext() throws IOException {

			while (!st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		private int readInt() throws IOException, NumberFormatException {

			return Integer.parseInt(readNext());

		}

		private long readLong() throws IOException, NumberFormatException {

			return Long.parseLong(readNext());

		}
	}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.StringTokenizer;

public class Main {
	public static class Union_Set {
		int parent[];
		int max_path[];

		public Union_Set(int[] parent, int max_path[]) {
			this.parent = parent;
			this.max_path = max_path;

		}

		public int getMaxPathById(int id) {

			return max_path[findParent(id)];
		}

		public int getMaxPathByParent(int parent) {
			return max_path[parent];
		}

		public int findParent(int i) {
			if (parent[i] == i)
				return i;
			else {
				int p = i;
				while (p != parent[p]){
					parent[p]=parent[parent[p]];
					p = parent[p];
				}
				parent[i] = p;
				return p;
			}
		}

		public void set_Union(int set1, int set2) {
			int parent1 = findParent(set1);
			int parent2 = findParent(set2);
			if (parent1 < parent2) {
				max_path[parent1] = max(max(max_path[parent1], max_path[parent2]),
						(max_path[parent1] + 1) / 2 + (max_path[parent2] + 1)/ 2 + 1);
				parent[parent2] = parent1;
			} else {
				if (parent1 > parent2) {
					max_path[parent2] = max(max(max_path[parent1], max_path[parent2]),
							(max_path[parent1] + 1) / 2+ (max_path[parent2] + 1) / 2 + 1);
					parent[parent1] = parent2;
				}

			}
		}

		public int max(int a, int b) {
			return a < b ? b : a;
		}
	}

	public static void depth(ArrayList<Integer> graph[], int[] parent,int[] max_path) {
		int end;
		int depth[] = new int[graph.length];
		boolean visited[] = new boolean[graph.length];
		LinkedList<Integer> queue = new LinkedList<Integer>();
		for (int i = 0; i < graph.length; i++) {
			if (!visited[i]) {
				end = bfs0(graph, parent, i,queue);
				if (end != i) {
					end = bfs(graph, depth, visited, end,queue);
					max_path[i] = depth[end];
				}else
					visited[i]=true;
			}
		}

	}

	public static int bfs0(ArrayList<Integer>[] graph, int[] parent, int start,LinkedList<Integer>queue) {
		int v = -1;
		int max = 0;
		int cur;
		boolean visited[] = new boolean[graph.length];
		int depth[] = new int[graph.length];
		queue.add(start);
		visited[start]=true;
		while (!queue.isEmpty()) {
			cur = queue.pollFirst();
			for (int u : graph[cur]) {
				if (!visited[u]) {
					depth[u] = depth[cur] + 1;
					queue.add(u);
					visited[u]=true;
					if (depth[u] > max) {
						max = depth[u];
						v = u;
					}
					parent[u] = start;
				}
			}
		}
		if (v == -1)
			return start;
		return v;

	}

	public static int bfs(ArrayList<Integer>[] graph, int depth[],boolean visited[], int start,LinkedList<Integer>queue) {
		int v = -1;
		int max = 0;
		int cur;
		queue.add(start);
		visited[start]=true;
		while (!queue.isEmpty()) {
			cur = queue.pollFirst();
			for (int u : graph[cur]) {
				if (!visited[u]) {
					depth[u] = depth[cur] + 1;
					queue.add(u);
					visited[u]=true;
					if (depth[u] > max) {
						max = depth[u];
						v = u;
					}
				}

			}
		}
		return v;

	}

	public static void main(String args[]) throws NumberFormatException,
			IOException {

		Stdin in = new Stdin();
		PrintWriter out = new PrintWriter(System.out);
		int n = in.readInt();
		int m = in.readInt();
		int q = in.readInt();
		int[] parent = new int[n];
		int[] max_path = new int[n];
		ArrayList<Integer> graph[] = new ArrayList[n];
		for (int i = 0; i < graph.length; i++)
			graph[i] = new ArrayList<Integer>();
		int a, b, type, x, y, p;
		for (int i = 0; i < n; i++) {
			parent[i] = i;
		}

		for (int i = 0; i < m; i++) {
			a = in.readInt() - 1;
			b = in.readInt() - 1;
			if (a != b) {
				graph[a].add(b);
				graph[b].add(a);
			}

		}
		depth(graph, parent, max_path);
		Union_Set union = new Union_Set(parent, max_path);
		for (int i = 0; i < q; i++) {
			type = in.readInt();
			if (type == 1) {
				x = in.readInt() - 1;
				p = union.findParent(x);
				out.println(union.getMaxPathByParent(p));
			} else {
				x = in.readInt() - 1;
				y = in.readInt() - 1;
				if (x != y) {
					union.set_Union(x, y);
				}
			}
		}

		out.flush();
		out.close();

	}

	private static class Stdin {
		InputStreamReader read;
		BufferedReader br;

		StringTokenizer st = new StringTokenizer("");

		private Stdin() {
			read = new InputStreamReader(System.in);
			br = new BufferedReader(read);

		}

		private String readNext() throws IOException {

			while (!st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		private int readInt() throws IOException, NumberFormatException {

			return Integer.parseInt(readNext());

		}

		private long readLong() throws IOException, NumberFormatException {

			return Long.parseLong(readNext());

		}
	}
}


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];
		Arrays.fill(dis, oo);
		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[c] = superParent;
				}
				if (dis[i] > dis[c] + 1) {
					dis[i] = dis[c] + 1;
					q[tail++] = i;
				}
			}
		}
		int v = x;
		int max = dis[v];
		for(int i=0;i<tail;i++){
			if (dis[q[i]] > max) {
				v = q[i];
				max = dis[q[i]];
			}
			dis[q[i]] = oo;
		}
		if (times == 0) return bfs(v, times+1);
		return max;
	}

	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.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[c] = 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.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;
	List<Integer> comp;

	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);
		}

		comp = new LinkedList<Integer>();
		used = new boolean[n];
		for(int i=0;i<n;i++){
			if (!used[i]) {
				comp.clear();
				dfs(i);
				// System.out.println("new comp:");
				for(int j : comp) {
					union(i, j);
					// System.out.println(j + " ");
				}
				// System.out.println();
				int id = find(i);
				d[id] = 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;
	}

	Queue<Integer> q;
	final static int oo = Integer.MAX_VALUE/2;

	private int bfs(int x, int times) {
		q = new ArrayDeque<Integer>();
		q.add(x);
		int []d = new int[n];
		Arrays.fill(d, oo);
		d[x] = 0;
		while(q.size() > 0) {
			int c = q.poll();
			for(int i : g[c]) {
				if (d[i] > d[c] + 1) {
					d[i] = d[c] + 1;
					q.add(i);
				}
			}
		}
		int v = x;
		for(int i : comp) {
			if (d[i] > d[v]) {
				v = i;
			}
		}
		if (times == 0) return bfs(v, times+1);
		return d[v];
	}

	private void dfs(int x) {
		used[x] = true;
		comp.add(x);
		for(int i : g[x]) {
			if (used[i]) continue;
			dfs(i);
		}
	}

	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.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;
	List<Integer> comp;

	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);
		}

		comp = new LinkedList<Integer>();
		used = new boolean[n];
		dis = new int[n];
		q = new int[n];
		for(int i=0;i<n;i++){
			if (!used[i]) {
				comp.clear();
				dfs(i, i);
				// System.out.println("new comp:");
				// for(int j : comp) {
				// 	union(i, j);
				// 	System.out.println(j + " ");
				// }
				// System.out.println();
				// int id = find(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;

		Arrays.fill(dis, oo);
		dis[x] = 0;
		while(head != tail) {
			int c = q[head++];
			for(int i : g[c]) {
				if (dis[i] > dis[c] + 1) {
					dis[i] = dis[c] + 1;
					q[tail++] = i;
					if (tail == q.length) tail = 0;
				}
			}
			if (head == q.length) head = 0;
		}
		int v = x;
		for(int i : comp) {
			if (dis[i] > dis[v]) {
				v = i;
			}
		}
		if (times == 0) return bfs(v, times+1);
		return dis[v];
	}

	private void dfs(int x, int superParent) {
		used[x] = true;
		p[x] = superParent;
		comp.add(x);
		for(int i : g[x]) {
			if (used[i]) continue;
			dfs(i, superParent);
		}
	}

	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();
	}
}