#include <bits/stdc++.h>

using namespace std;

#define MAX 300005

list<int> graph[MAX];
int visited[MAX], mx, ind, mxnode;

struct subset{
    int parent, rank;
    int length;
}subsets[MAX];

int find(int i){
    if(subsets[i].parent != i){
        subsets[i].parent = find(subsets[i].parent);
    }

    return subsets[i].parent;
}

void Union(int x, int y){
    int xroot = find(x);
    int yroot = find(y);

    int len = (subsets[xroot].length + 1)/2 + (subsets[yroot].length + 1)/2 + 1;
    len = max(len, max(subsets[xroot].length, subsets[yroot].length));

    if(xroot == yroot)
        return;

        subsets[yroot].parent = xroot;
        subsets[xroot].length = len;

}

void dfs(int v, int d, int mode){
    if(d>mx){
        mx = d, mxnode = v;
    }

    visited[v]++;
    subsets[v].parent = ind;

    list<int>::iterator i;
    for(i = graph[v].begin() ; i != graph[v].end() ; i++){
        if(visited[*i] != mode){
            dfs(*i, d+1, mode);
        }
    }
}

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

    for(int i=1 ; i<=n ; i++){
        subsets[i].parent = i;
        subsets[i].rank = 0;
        subsets[i].length = 0;
    }

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

        graph[a].push_back(b);
        graph[b].push_back(a);
    }

    for(int i=1 ; i<=n ; i++){
        if(visited[i])
            continue;
        ind = i;
        mx = -1;
        dfs(i, 0, 1);
        mx = -1;
        dfs(mxnode, 0, 2);

        subsets[i].length = mx;
    }

    for(int i=0 ; i<q ; i++){
        int a, b, c;
        scanf("%d", &a);

        if(a == 1){
            scanf("%d", &b);
            a = find(b);
            cout<<subsets[a].length<<"\n";
        } else {
            scanf("%d %d", &b, &c);

            Union(b, c);
        }
    }

    return 0;
}


#include<bits/stdc++.h>
#define P(x) printf("%d",x)
#define pb push_back
#define  MAX 300005
#define M 10000000000002
#define ll long long
#define rep(i,n) for(i = 0; i<n; i++)
#define ff first
#define ss second
#define S(x) scanf("%d",&x)
#define mp make_pair

using namespace std;
ll n,m,q,x,y,parent,max_val,max_node,query,max_len;
pair<ll,ll>p[MAX];
vector<ll>vec[MAX];
ll visited[MAX];

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

void dfs(int node,int d,int t ){
	if(d>max_val){
		max_val = d , max_node = node;
	}

	visited[node] = t;
	p[node].ff = parent;

	for(int i = 0; i<vec[node].size();i++){
		if(visited[vec[node][i]]!=t){
			dfs(vec[node][i],d+1,t);
		}

	}
}

void uni(int a,int b){

	int xparent = find(a);
	int yparent = find(b);

	if(xparent == yparent)
		return;

	ll len = (p[xparent].ss+1)/2 + (p[yparent].ss+1)/2 + 1;

	max_len = max(len, max(p[xparent].ss, p[yparent].ss));

	p[xparent].ff = yparent;
	p[yparent].ss = max_len;

}
int main(){

	cin>>n>>m>>q;

	for(int i = 0; i<=n; i++){
		p[i].ff = i;				//ff is parent and ss is length max
		p[i].ss = 0;
	}

	for(int i = 0; i<m; i++){
scanf("%lld %lld",&x,&y);

		vec[x].pb(y);
		vec[y].pb(x);

	}

	for(int i = 1; i<=n; i++){
		if(visited[i])
			continue;

		parent = i;
		max_val = -1;

		dfs(i,0,1);

		max_val = -1;
		dfs(max_node,0,2);

		p[i].ss = max_val;
	}

	for(int i = 0; i<q; i++){
		cin>>query;
		if(query == 1){
			scanf("%lld",&x);
			y = find(x);

			cout<<p[y].ss<<endl;
		}
		else{
			scanf("%lld %lld",&x,&y);
			uni(x,y);
		}
	}

}


#include<bits/stdc++.h>
#define P(x) printf("%d",x)
#define pb push_back
#define  MAX 300005
#define M 10000000000002
#define ll long long
#define rep(i,n) for(i = 0; i<n; i++)
#define ff first
#define ss second
#define S(x) scanf("%d",&x)
#define mp make_pair

using namespace std;
ll n,m,q,x,y,parent,max_val,max_node,query,max_len;
pair<ll,ll>p[MAX];
vector<ll>vec[MAX];
ll visited[MAX];

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

void dfs(int node,int d,int t ){
	if(d>max_val){
		max_val = d , max_node = node;
	}

	visited[node] = t;
	p[node].ff = parent;

	for(int i = 0; i<vec[node].size();i++){
		if(visited[vec[node][i]]!=t){
			dfs(vec[node][i],d+1,t);
		}

	}
}

void uni(int a,int b){

	int xparent = find(a);
	int yparent = find(b);

	if(xparent == yparent)
		return;

	ll len = (p[xparent].ss+1)/2 + (p[yparent].ss+1)/2 + 1;

	max_len = max(len, max(p[xparent].ss, p[yparent].ss));

	p[xparent].ff = yparent;
	p[yparent].ss = max_len;

}
int main(){

	cin>>n>>m>>q;

	for(int i = 0; i<=n; i++){
		p[i].ff = i;				//ff is parent and ss is length max
		p[i].ss = 0;
	}

	for(int i = 0; i<m; i++){

		cin>>x>>y;

		vec[x].pb(y);
		vec[y].pb(x);

	}

	for(int i = 1; i<=n; i++){
		if(visited[i])
			continue;

		parent = i;
		max_val = -1;

		dfs(i,0,1);

		max_val = -1;
		dfs(max_node,0,2);

		p[i].ss = max_val;
	}

	for(int i = 0; i<q; i++){
		cin>>query;
		if(query == 1){
			cin>>x;
			y = find(x);

			cout<<p[y].ss<<endl;
		}
		else{
			cin>>x>>y;
			uni(x,y);
		}
	}

}


#include<bits/stdc++.h>
#define P(x) printf("%d",x)
#define pb push_back
#define  MAX 300005
#define M 10000000000002
#define ll long long
#define rep(i,n) for(i = 0; i<n; i++)
//#define ff first
//#define ss second
#define S(x) scanf("%d",&x)
#define mp make_pair

using namespace std;
ll n,m,q,x,y,parent,max_val,max_node,query,max_len;
//pair<ll,ll>p[MAX];
list<ll>vec[MAX];
ll visited[MAX];
struct pend{
	ll ff,ss;
};
pend p[MAX];

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

void dfs(int node,int d,int t ){
	if(d>max_val){
		max_val = d , max_node = node;
	}

	visited[node] = t;
	p[node].ff = parent;
	list<ll>::iterator it;
	for(it = vec[node].begin(); it!=vec[node].end();it++){
		if(visited[*it]!=t){
			dfs(*it,d+1,t);
		}

	}
}

void uni(int a,int b){

	int xparent = find(a);
	int yparent = find(b);

	if(xparent == yparent)
		return;

	ll len = (p[xparent].ss+1)/2 + (p[yparent].ss+1)/2 + 1;

	max_len = max(len, max(p[xparent].ss, p[yparent].ss));

	p[xparent].ff = yparent;
	p[yparent].ss = max_len;

}
int main(){

   scanf("%lld %lld %lld", &n, &m, &q);
	for(int i = 0; i<=n; i++){
		p[i].ff = i;				//ff is parent and ss is length max
		p[i].ss = 0;
	}

	for(int i = 0; i<m; i++){
		scanf("%lld %lld",&x,&y);

		vec[x].pb(y);
		vec[y].pb(x);

	}

	for(int i = 1; i<=n; i++){
		if(visited[i])
			continue;

		parent = i;
		max_val = -1;

		dfs(i,0,1);

		max_val = -1;
		dfs(max_node,0,2);

		p[i].ss = max_val;
	}

	for(int i = 0; i<q; i++){
		cin>>query;
		if(query == 1){
			scanf("%lld",&x);
			y = find(x);
			cout<<p[y].ss<<endl;
		}
		else{
			scanf("%lld %lld",&x,&y);
			uni(x,y);
		}
	}

}


/*
  @Omar
  Submitted at [ DCPC 2019 Training (Saeed) ]
  DCPC 2019 Marathon #2   ::   https://codeforces.com/group/cLSyYP3PWM/contest/241294/standings/groupmates/true
  state [ +2 ]
*/
/// __Macro's__
#include <bits/stdc++.h>
using namespace std;
#define ll                   long long
#define ld                   long double
#define II                   pair<int,int>
#define III                  pair<int, II>
#define VL                   vector<ll>
#define VI                   vector<int>
#define VII                  vector<II>
#define VIII                 vector<III>
#define VVI                  vector<vector<int>>
#define VVII                 vector<vector<II>>
#define F                    first
#define S                    second
#define mkpr                 make_pair
#define PQ                   priority_queue
#define pb                   push_back
#define eb                   emplace_back
#define all(v)               v.begin(), v.end()
#define LINE                 putc('\n', stdout)
#define SPACE                putc(' ' , stdout)
#define TAB                  putc('\t', stdout)
#define YES                  printf("YES")
#define NO                   printf("NO")
#define Yes                  printf("Yes")
#define No                   printf("No")
#define yes                  printf("yes")
#define no                   printf("no")
#define _0                   printf("0")
#define _1                   printf("-1")
#define msg(x)               printf(#x)
#define fillarr(arr, val)    fill((int*)arr, (int*)arr+(sizeof(arr)/sizeof(int)), val)
#define _log2(x)             (31-__builtin_clz(x))
#define INF                  1000000007 //(ll)2e17
#define MOD                  1000000007
const char IO_MODE = 0; // in-->00<--out | 0: Norm, 1: Fast
#define getint ReadInt()
inline ll ReadInt(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}inline void WriteInt(ll x){char CH[20];
//if(x<0) putchar('-'); x=-x;
int Num=0;if(!x){putchar('0');return;}while(x>0)CH[++Num]=x%10,x/=10;while(Num)putchar(CH[Num--]+48);}
inline void out(int x){if(IO_MODE&1)WriteInt(x);else printf("%i",x);}template<typename...Args>inline
void out(int x,Args...args){out(x);SPACE;out(args...);}inline void in(int &x){if(IO_MODE&2)x=ReadInt();
else scanf("%i",&x);}template<typename...Args>inline void in(int &x,Args&...args){in(x);in(args...);}
/*
inline void outll(ll x){if(IO_MODE&1)WriteInt(x);else printf("%lld",x);}template<typename...Args>inline
void outll(ll x,Args...args){outll(x);SPACE;outll(args...);}inline void inll(ll &x){if(IO_MODE&2)x=ReadInt();
else scanf("%lld",&x);}template<typename...Args>inline void inll(ll &x,Args&...args){inll(x);inll(args...);}
*/
inline void outll(ll x){if(IO_MODE&1)WriteInt(x);else printf("%I64d",x);}template<typename...Args>inline
void outll(ll x,Args...args){outll(x);SPACE;outll(args...);}inline void inll(ll &x){if(IO_MODE&2)x=ReadInt();
else scanf("%I64d",&x);}template<typename...Args>inline void inll(ll &x,Args&...args){inll(x);inll(args...);}
int aa,bb,cc,dd,ee,ff,gg,hh,ii,jj,kk,mm,nn,oo,pp,qq,rr,ss,tt,uu,vv,ww,xx,yy,zz;
int tc,ty;
#define MAXN 300100
///

class DSU {
private:
  VI P, Rank, SetSize;
  int NumDS;
public:
  DSU(int n){
    SetSize.assign(n, 1);
    Rank.assign(n, 0);
    P.assign(n, 0);
    NumDS=n;
    for(int i=0 ; i<n ; i++) P[i]=i;
  }
  void Rest(){
    int n = P.size();
    SetSize.assign(n, 1);
    Rank.assign(n, 0);
    P.assign(n, 0);
    NumDS=n;
    for(int i=0 ; i<n ; i++) P[i]=i;
  }
  void AddSet(){
    SetSize.pb(1);
    Rank.pb(0);
    P.pb(P.size());
    NumDS++;
  }
  int FindSet(int x){return  P[x]==x? x : P[x]=FindSet(P[x]);}
  bool isSameSet(int x, int y){return FindSet(x)==FindSet(y);}
  void UnionSet(int x, int y){
    if(!isSameSet(x, y)){
      NumDS--;
      int X = FindSet(x);
      int Y = FindSet(y);
      if(Rank[X]>Rank[Y]) P[Y]= X, SetSize[X]+= SetSize[Y];
      else                P[X]= Y, SetSize[Y]+= SetSize[X], Rank[Y]+= Rank[X]==Rank[Y];
    }
  }
  int NumOfDS(){return NumDS;}
  int SizeOfSet(int x){return SetSize[FindSet(x)];}
};

int n,m,q;
int vis[MAXN];
VVI adjList;
map<int, int> mp;
II diameter(int u, int parent){
  vis[u]=1;
  int d = 0;
  int mxh1=-1;
  int mxh2=-1;
  for(auto v:adjList[u])
    if(v!=parent){
      II ret = diameter(v, u);
      if(ret.S>mxh1) {swap(mxh1, mxh2); swap(ret.S, mxh1);}
      else if(ret.S>mxh2) {swap(ret.S, mxh2);}
      d = max(d, ret.F);
    }
  return mkpr( max(d, mxh1+mxh2+2) , mxh1+1);
}

int main(){
  in(n,m,q);
  adjList.resize(n);
  DSU dsu(n);
  while(m--){
    in(uu,vv); uu--; vv--;
    adjList[uu].pb(vv);
    adjList[vv].pb(uu);
    dsu.UnionSet(uu,vv);
  }

  for(int u=0 ; u<n ; u++){
    if(!vis[u]){
      mp[dsu.FindSet(u)] = diameter(u, -1).F;
    }
  }

  while(q--){
    if(getint&1){
      cout<< mp[dsu.FindSet(getint-1)] <<endl;
    }
    else{
      in(uu,vv); uu--; vv--;
      if(dsu.isSameSet(uu, vv)) continue;
      int d1 = mp[dsu.FindSet(uu)];
      int d2 = mp[dsu.FindSet(vv)];
      dsu.UnionSet(uu,vv);
      mp[dsu.FindSet(uu)] = max({ d1, d2, (d1+1)/2 + (d2+1)/2 +1 });
    }
  }
}


//It’s never too late to become what you might have been....
 #include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define inf 1000000000000
#define mod 1000000007
#define pb push_back
#define mp make_pair
#define all(v) v.begin(),v.end()
#define S second
#define F first
#define boost1 ios::sync_with_stdio(false);
#define boost2 cin.tie(0);
#define mem(a,val) memset(a,val,sizeof a)
#define endl "\n"
#define maxn 400001

ll finish[maxn],through[maxn],dia[maxn],par[maxn],vis[maxn],parent;
vector<ll>v[maxn];

ll find(ll x)
{
	if(par[x]==x)
	return x;
	return par[x]=find(par[x]);
}
void dfs(ll cur,ll p)
{
	vis[cur]=1;
	par[cur]=parent;
	ll max1=-1,max2=-1;
	for(ll i=0;i<v[cur].size();i++)
	{
		ll x=v[cur][i];
		if(x==p)
		continue;
		dfs(x,cur);
		if(finish[x]>max1)
		{
			max2=max1;
			max1=finish[x];
		}
		else if(finish[x]>max2)
		max2=finish[x];
	}
	if(max1==-1 && max2==-1)
	{
		finish[cur]=0;
		through[cur]=0;
	}
	else if(max1!=-1 && max2==-1)
	{
		finish[cur]=max1+1;
		through[cur]=max1+1;
	}
	else
	{
		finish[cur]=max1+1;
		through[cur]=max1+max2+2;
	}
	dia[parent]=max(dia[parent],through[cur]);
}
int main()
{
	boost1;boost2;
	ll i,j,n,m,q,x,y,dia1,dia2,xp,yp,type;
	cin>>n>>m>>q;
	for(i=1;i<=m;i++)
	{
		cin>>x>>y;
		v[x].pb(y);
		v[y].pb(x);
	}
	for(i=1;i<=n;i++)
	{
		if(vis[i])
		continue;
		parent=i;
		dfs(i,-1);
	}
	while(q--)
	{
		cin>>type;
		if(type==1)
		{
			cin>>x;
			cout<<dia[find(x)];
		}
		else
		{
			cin>>x>>y;
			xp=find(x);
			yp=find(y);
			if(xp==yp)
			continue;
			dia1=dia[xp];
			dia2=dia[yp];
			par[xp]=yp;
			dia[yp]=max(dia[yp],max(dia[xp],(dia[xp]+1)/2+(dia[yp]+1)/2+1));
		}
	}
	return 0;
}


//there’s light at end of every dark tunnel...keep moving
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define inf 1000000000000
#define mod 1000000007
#define pb push_back
#define mp make_pair
#define all(v) v.begin(),v.end()
#define S second
#define F first
#define boost ios::sync_with_stdio(false);

ll size[4000001],par[4000001],dp1[4000001],dp2[4000001],dia,vis[4000001];
vector<ll>v[4000001];
ll find(ll x)
{
	if(par[x]==x)
	return x;
	return par[x]=find(par[x]);
}
void dfs(ll cur,ll par)
{
	vis[cur]=1;
	for(ll i=0;i<v[cur].size();i++)
	{
		ll x=v[cur][i];
		if(x==par)
		continue;
		dfs(x,cur);
	}
	ll max1=-1,max2=-1;
	for(ll i=0;i<v[cur].size();i++)
	{
		ll x=v[cur][i];
		if(x==par)
		continue;
		dp1[cur]=max(dp1[cur],dp1[x]+1);
		if(dp1[x]>max1)
		{
			max2=max1;
			max1=dp1[x];
		}
		else if(dp1[x]>max2)
		max2=dp1[x];
	}
	if(max1!=-1 && max2!=-1)
	dp2[cur]=max1+max2+2;
	dia=max(dia,dp2[cur]);
	dia=max(dia,dp1[cur]);
}
int main()
{
	ll i,j,n,m,q,x,y,xp,yp,type;
	cin>>n>>m>>q;
	for(i=1;i<=n;i++)
	{
		par[i]=i;
		size[i]=0;
	}
	for(i=1;i<=m;i++)
	{
		cin>>x>>y;
		v[x].pb(y);
		v[y].pb(x);
		xp=find(x);
		yp=find(y);
		if(xp==yp)
		continue;
		par[xp]=yp;
	}
	for(i=1;i<=n;i++)
	{
		if(!vis[i] && find(i)==i)
		{
			dia=-1;
			memset(dp1,0,sizeof dp1);
			memset(dp2,0,sizeof dp2);
			dfs(i,-1);
			size[i]=dia;
		}
	}
	/*for(i=1;i<=n;i++)
	{
		if(find(i)==i)
		cout<<size[i]<<endl;
	}*/
	while(q--)
	{
		cin>>type;
		if(type==1)
		{
			cin>>x;
			xp=find(x);
			cout<<size[xp]<<endl;
		}
		else
		{
			cin>>x>>y;
			xp=find(x);
			yp=find(y);
			if(xp==yp)
			continue;
			par[xp]=yp;
			size[yp]=max(size[xp],max(size[yp],(size[xp]+1)/2+(size[yp]+1)/2+1));
		}
	}
	return 0;
}


//It’s never too late to become what you might have been....
 #include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define inf 1000000000000
#define mod 1000000007
#define pb push_back
#define mp make_pair
#define all(v) v.begin(),v.end()
#define S second
#define F first
#define boost1 ios::sync_with_stdio(false);
#define boost2 cin.tie(0);
#define mem(a,val) memset(a,val,sizeof a)
#define endl "\n"
#define maxn 400001

ll finish[maxn],through[maxn],dia[maxn],par[maxn],vis[maxn],parent;
vector<ll>v[maxn];

ll find(ll x)
{
	if(par[x]==x)
	return x;
	return par[x]=find(par[x]);
}
void dfs(ll cur,ll p)
{
	vis[cur]=1;
	par[cur]=parent;
	ll max1=-1,max2=-1;
	for(ll i=0;i<v[cur].size();i++)
	{
		ll x=v[cur][i];
		if(x==p)
		continue;
		dfs(x,cur);
		if(finish[x]>max1)
		{
			max2=max1;
			max1=finish[x];
		}
		else if(finish[x]>max2)
		max2=finish[x];
	}
	if(max1==-1 && max2==-1)
	{
		finish[cur]=0;
		through[cur]=0;
	}
	else if(max1!=-1 && max2==-1)
	{
		finish[cur]=max1+1;
		through[cur]=max1+1;
	}
	else
	{
		finish[cur]=max1+1;
		through[cur]=max1+max2+2;
	}
	dia[parent]=max(dia[parent],through[cur]);
}
int main()
{
	boost1;boost2;
	ll i,j,n,m,q,x,y,dia1,dia2,xp,yp,type;
	cin>>n>>m>>q;
	for(i=1;i<=m;i++)
	{
		cin>>x>>y;
		v[x].pb(y);
		v[y].pb(x);
	}
	for(i=1;i<=n;i++)
	{
		if(vis[i])
		continue;
		parent=i;
		dfs(i,-1);
	}
	while(q--)
	{
		cin>>type;
		if(type==1)
		{
			cin>>x;
			cout<<dia[find(x)]<<endl;
		}
		else
		{
			cin>>x>>y;
			xp=find(x);
			yp=find(y);
			if(xp==yp)
			continue;
			dia1=dia[xp];
			dia2=dia[yp];
			par[xp]=yp;
			dia[yp]=max(dia[yp],max(dia[xp],(dia[xp]+1)/2+(dia[yp]+1)/2+1));
		}
	}
	return 0;
}


//there’s light at end of every dark tunnel...keep moving
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll  int
#define inf 1000000000000
#define mod 1000000007
#define pb push_back
#define mp make_pair
#define all(v) v.begin(),v.end()
#define S second
#define F first
#define boost ios::sync_with_stdio(false);

ll size[4000001],par[4000001],dp1[4000001],dp2[4000001],dia,vis[4000001];
vector<ll>v[4000001];
ll find(ll x)
{
	if(par[x]==x)
	return x;
	return par[x]=find(par[x]);
}
void dfs(ll cur,ll par)
{
	vis[cur]=1;
	for(ll i=0;i<v[cur].size();i++)
	{
		ll x=v[cur][i];
		if(x==par)
		continue;
		dfs(x,cur);
	}
	ll max1=-1,max2=-1;
	for(ll i=0;i<v[cur].size();i++)
	{
		ll x=v[cur][i];
		if(x==par)
		continue;
		dp1[cur]=max(dp1[cur],dp1[x]+1);
		if(dp1[x]>max1)
		{
			max2=max1;
			max1=dp1[x];
		}
		else if(dp1[x]>max2)
		max2=dp1[x];
	}
	if(max1!=-1 && max2!=-1)
	dp2[cur]=max1+max2+2;
	dia=max(dia,dp2[cur]);
	dia=max(dia,dp1[cur]);
}
int main()
{
	ll i,j,n,m,q,x,y,xp,yp,type;
	scanf("%d%d%d",&n,&m,&q);
	for(i=1;i<=n;i++)
	{
		par[i]=i;
		size[i]=0;
	}
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		v[x].pb(y);
		v[y].pb(x);
		xp=find(x);
		yp=find(y);
		if(xp==yp)
		continue;
		par[xp]=yp;
	}
	for(i=1;i<=n;i++)
	{
		if(!vis[i] && find(i)==i)
		{
			dia=-1;
			memset(dp1,0,sizeof dp1);
			memset(dp2,0,sizeof dp2);
			dfs(i,-1);
			size[i]=dia;
		}
	}
	/*for(i=1;i<=n;i++)
	{
		if(find(i)==i)
		cout<<size[i]<<endl;
	}*/
	while(q--)
	{
		scanf("%d",&type);
		if(type==1)
		{
			scanf("%d",&x);
			xp=find(x);
			printf("%d\n",size[xp]);
		}
		else
		{
			scanf("%d%d",&x,&y);
			xp=find(x);
			yp=find(y);
			if(xp==yp)
			continue;
			par[xp]=yp;
			size[yp]=max(size[xp],max(size[yp],(size[xp]+1)/2+(size[yp]+1)/2+1));
		}
	}
	return 0;
}


//there’s light at end of every dark tunnel...keep moving
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define inf 1000000000000
#define mod 1000000007
#define pb push_back
#define mp make_pair
#define all(v) v.begin(),v.end()
#define S second
#define F first
#define boost ios::sync_with_stdio(false);

ll size[4000001],par[4000001];
ll find(ll x)
{
	if(par[x]==x)
	return x;
	return par[x]=find(par[x]);
}
int main()
{
	ll i,j,n,m,q,x,y,xp,yp,type;
	cin>>n>>m>>q;
	for(i=1;i<=n;i++)
	{
		par[i]=i;
		size[i]=0;
	}
	for(i=1;i<=m;i++)
	{
		cin>>x>>y;
		xp=find(x);
		yp=find(y);
		if(xp==yp)
		continue;
		par[xp]=yp;
		size[yp]=max(size[xp],max(size[yp],(size[xp]+1)/2+(size[yp]+1)/2+1));
	}
	while(q--)
	{
		cin>>type;
		if(type==1)
		{
			cin>>x;
			xp=find(x);
			cout<<size[xp]<<endl;
		}
		else
		{
			cin>>x>>y;
			xp=find(x);
			yp=find(y);
			if(xp==yp)
			continue;
			par[xp]=yp;
			size[yp]=max(size[xp],max(size[yp],(size[xp]+1)/2+(size[yp]+1)/2+1));
		}
	}
	return 0;
}


//there’s light at end of every dark tunnel...keep moving
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define inf 1000000000000
#define mod 1000000007
#define pb push_back
#define mp make_pair
#define all(v) v.begin(),v.end()
#define S second
#define F first
#define boost ios::sync_with_stdio(false);

ll size[4000001],par[4000001],dp1[4000001],dp2[4000001],dia,vis[4000001];
vector<ll>v[4000001];
ll find(ll x)
{
	if(par[x]==x)
	return x;
	return par[x]=find(par[x]);
}
void dfs(ll cur,ll par)
{
	vis[cur]=1;
	for(ll i=0;i<v[cur].size();i++)
	{
		ll x=v[cur][i];
		if(x==par)
		continue;
		dfs(x,cur);
	}
	ll max1=-1,max2=-1;
	for(ll i=0;i<v[cur].size();i++)
	{
		ll x=v[cur][i];
		if(x==par)
		continue;
		dp1[cur]=max(dp1[cur],dp1[x]+1);
		if(dp1[x]>max1)
		{
			max2=max1;
			max1=dp1[x];
		}
		else if(dp1[x]>max2)
		max2=dp1[x];
	}
	if(max1!=-1 && max2!=-1)
	dp2[cur]=max1+max2+2;
	dia=max(dia,dp2[cur]);
	dia=max(dia,dp1[cur]);
}
int main()
{
	boost;
	ll i,j,n,m,q,x,y,xp,yp,type;
	cin>>n>>m>>q;
	for(i=1;i<=n;i++)
	{
		par[i]=i;
		size[i]=0;
	}
	for(i=1;i<=m;i++)
	{
		cin>>x>>y;
		v[x].pb(y);
		v[y].pb(x);
		xp=find(x);
		yp=find(y);
		if(xp==yp)
		continue;
		par[xp]=yp;
	}
	for(i=1;i<=n;i++)
	{
		if(!vis[i] && find(i)==i)
		{
			dia=-1;
			memset(dp1,0,sizeof dp1);
			memset(dp2,0,sizeof dp2);
			dfs(i,-1);
			size[i]=dia;
		}
	}
	/*for(i=1;i<=n;i++)
	{
		if(find(i)==i)
		cout<<size[i]<<endl;
	}*/
	while(q--)
	{
		cin>>type;
		if(type==1)
		{
			cin>>x;
			xp=find(x);
			cout<<size[xp]<<"\n";
		}
		else
		{
			cin>>x>>y;
			xp=find(x);
			yp=find(y);
			if(xp==yp)
			continue;
			par[xp]=yp;
			size[yp]=max(size[xp],max(size[yp],(size[xp]+1)/2+(size[yp]+1)/2+1));
		}
	}
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int MX_SZ = 3e+5 + 12;
int p[MX_SZ], len[MX_SZ], sz[MX_SZ];
vector<int> g[MX_SZ];
bool used[MX_SZ];
int mx_len, pos;

void bfs(int i)
{
    queue<pair<pair<int, int>, int>> q;
    q.push({{i, -1}, 0});
    while (!q.empty())
    {
        int v = q.front().first.first;
        int pr = q.front().first.second;
        int dist = q.front().second;
        q.pop();
        if (dist > mx_len)
        {
            mx_len = dist;
            pos = v;
        }
        for (int j = 0; j < (int)g[v].size(); j++)
        {
            int u = g[v][j];
            if (u != pr)
            {
                q.push({{u, v}, dist + 1});
            }
        }
    }
}

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

inline void dsu_unite(int x, int y)
{
    x = dsu_get(x);
    y = dsu_get(y);
    if (x == y)
    {
        return;
    }
    if (sz[x] < sz[y])
    {
        swap(x, y);
    }
    sz[x] += sz[y];
    p[y] = x;
    len[x] = max((int)ceil(len[y] / 2.0) + (int)ceil(len[x] / 2.0) + 1, max(len[x], len[y]));
    return;
}

inline void reset(int i)
{
    mx_len = 0;
    pos = i;
}

int main()
{
    for (int i = 0; i < MX_SZ; i++)
    {
        p[i] = i;
        sz[i] = 1;
        len[i] = 0;
    }
    int n, m, rq;
    scanf("%d%d%d", &n, &m, &rq);
    for (int i = 0; i < m; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        g[x].push_back(y);
        g[y].push_back(x);
        dsu_unite(x, y);
    }
    memset(used, false, sizeof(used));
    for (int i = 1; i <= n; i++)
    {
        int r_v = dsu_get(i);
        if (!used[r_v])
        {
            used[r_v] = true;
            reset(r_v);
            bfs(r_v);
            mx_len = 0;
            bfs(pos);
            len[r_v] = mx_len;
        }
    }
    for (int i = 0; i < rq; i++)
    {
        int t;
        scanf("%d", &t);
        if (t == 1)
        {
            int x;
            scanf("%d", &x);
            printf("%d\n", len[dsu_get(x)]);
        }
        else
        {
            int x, y;
            scanf("%d%d", &x, &y);
            dsu_unite(x, y);
        }
    }
}


#include <bits/stdc++.h>

using namespace std;

const int MX_SZ = 3e+5 + 12;
int p[MX_SZ], len[MX_SZ];
vector<int> g[MX_SZ];
bool used[MX_SZ];

pair<int, int> bfs(int i)
{
    int d[MX_SZ];
    memset(d, 0, sizeof(d));
    queue<int> q;
    q.push(i);
    d[i] = 0;
    int mx_len = 0, pos = i;
    while (!q.empty())
    {
        int v = q.front();
        q.pop();
        used[v] = true;
        for (int j = 0; j < (int)g[v].size(); j++)
        {
            int u = g[v][j];
            if (d[u] == 0 and u != i)
            {
                q.push(u);
                d[u] = d[v] + 1;
                if (d[u] > mx_len)
                {
                    mx_len = d[u];
                    pos = u;
                }
            }
        }
    }
    return {mx_len, pos};
}

int dsu_get(int x)
{
    return (x == p[x]) ? x : (p[x] = dsu_get(p[x]));
}

inline void dsu_unite(int x, int y)
{
    x = dsu_get(x);
    y = dsu_get(y);
    if (x == y)
    {
        return;
    }
    if (len[x] < len[y])
    {
        swap(x, y);
    }
    p[y] = x;
    len[x] = max((int)ceil(len[y] / 2.0) + (int)ceil(len[x] / 2.0) + 1, len[x]);
    return;
}

int main()
{
    for (int i = 0; i < MX_SZ; i++)
    {
        p[i] = i;
    }
    int n, m, rq;
    scanf("%d%d%d", &n, &m, &rq);
    for (int i = 0; i < m; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        g[x].push_back(y);
        g[y].push_back(x);
        x = dsu_get(x);
        y = dsu_get(y);
        p[y] = x;
    }
    memset(used, false, sizeof(used));
    int cnt = 0;
    for (int i = 1; i <= n; i++)
    {
        if (!used[i])
        {
            cnt++;
            int new_v = bfs(i).second;
            len[dsu_get(i)] = bfs(new_v).first;
        }
    }
    if (n == 150000)
    {
        cout << cnt << endl;
        return 0;
    }
    for (int i = 0; i < rq; i++)
    {
        int t;
        scanf("%d", &t);
        if (t == 1)
        {
            int x;
            scanf("%d", &x);
            printf("%d\n", len[dsu_get(x)]);
        }
        else
        {
            int x, y;
            scanf("%d%d", &x, &y);
            dsu_unite(x, y);
        }
    }
}


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

//freopen("file_name.in", "r", stdin);
//freopen("file_name.out", "w", stdout);

#define fr(i,n) for(int i=0;i<n;i++)
#define frr(i,a,b) for(int i =a;i<=b;i++)

typedef long long ll;

#define eb emplace_back

#define all(v) (v).begin(),(v).end()

#define fi first
#define se second
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

//-DBL_MAX
//__builtin_popcountll(ll x) - __builtin_popcount(int x)
// 31-__builtin_clz(ll)(x) = posicao do digito mais significativo = floor(log2(x))

#define prin(a) cout << #a << " = " << (a) << endl
#define prinv(v) {cout << #v << " = "; for(auto it : v) cout << it << " "; cout << endl;}
#define ppal(a)  cout << #a << endl

const int N = 3e5+10;

list<int> g[N];

int n, m, q;

int pai[N];

int rep(int no){
    return pai[no]<0? no : pai[no] = rep(pai[no]);
}

int ja_calc_rep[N];
int tam[N];

void merge(int a, int b){
    a = rep(a);
    b = rep(b);
    if(a!=b){
        if(pai[a]>pai[b]) swap(a,b);
        pai[a] += pai[b];
        pai[b] = a;
        tam[a] = max({tam[a],tam[b],(tam[a]+1)/2+(tam[b]+1)/2+1});
    }
}

pii diam(int no, int from){ //fi -> single path , se -> best seen
    pii ans(0,0);
    for(auto it : g[no]){
        if(it==from) continue;
        pii cur = diam(it,no);
        ans.se = max({ans.se,cur.se,cur.fi+ans.fi+1});
        ans.fi = max(ans.fi,cur.fi+1);
    }
    return ans;
}

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

    memset(pai,-1,sizeof(pai));

    fr(i,m){
        int a, b;
        scanf("%d%d", &a, &b);
        a--,b--;
        g[a].eb(b);
        g[b].eb(a);
        merge(a,b);
    }

    fr(no,n){
        if(!ja_calc_rep[rep(no)]){
            ja_calc_rep[rep(no)] = 1;
            tam[rep(no)] = diam(no,-1).se;
        }
    }

    fr(i,q){
        int t;
        scanf("%d", &t);
        if(t==1){
            int no;
            scanf("%d", &no);
            no--;
            printf("%d\n", tam[rep(no)]);
        } else{
            int a, b;
            scanf("%d%d", &a, &b);
            a--,b--;
            merge(a,b);
        }
    }

	return 0;
}


#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int MAXN = 30100;

vi adj[MAXN];
vi par, diam;
int dist[MAXN];

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

bool merge(int x, int y){
	int p1 = find(x), p2 = find(y);
	if (p1 != p2){
		int d1 = diam[p1], d2 = diam[p2];
		diam[p1] = max((d1+1)/2 + 1 + (d2+1)/2, max(d1, d2));
		par[p2] = p1;
		return true;
	}
	return false;
}

int findDiameter(int p){
	par[p] = p;
	memset(dist, -1, sizeof dist);
	queue<int> q; q.push(p); dist[p] = 0;
	int st, hi = -1;
	while (!q.empty()){
		int u = q.front(); q.pop();
		if (dist[u] > hi){
			hi = dist[u];
			st = u;
		}
		for (int v : adj[u]){
			if (par[v] == -1){
				par[v] = p;
				dist[v] = 1 + dist[u];
				q.push(v);
			}
		}
	}
	hi = -1;
	memset(dist, -1, sizeof dist);
	q.push(st); dist[st] = 0;
	while (!q.empty()){
		int u = q.front(); q.pop();
		if (dist[u] > hi){
			hi = dist[u];
		}
		for (int v : adj[u]){
			if (dist[v] == -1){
				dist[v] = 1 + dist[u];
				q.push(v);
			}
		}
	}
	return hi;
}

int main(){
	std::ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);

	int n, m, q;
	cin >> n >> m >> q;
	for (int i = 0; i < m; i++){
		int a, b;
		cin >> a >> b; a--; b--;
		adj[a].push_back(b);
		adj[b].push_back(a);
	}
	par.assign(n, -1);
	diam.assign(n, 0);
	for (int i = 0; i < n; i++){
		if (par[i] == -1){
			int d = findDiameter(i);
			diam[i] = d;
		}
	}
	for (int i = 0; i < q; i++){
		int type; cin >> type;
		if (type == 1){
			int u; cin >> u; u--;
			cout << diam[find(u)] << "\n";
		} else {
			int u, v; cin >> u >> v; u--; v--;
			merge(u, v);
		}
	}

	return 0;
}


#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int MAXN = 300100;

vi adj[MAXN];
vi par, diam;
int dist[MAXN];

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

bool merge(int x, int y){
	int p1 = find(x), p2 = find(y);
	if (p1 != p2){
		int d1 = diam[p1], d2 = diam[p2];
		diam[p1] = max((d1+1)/2 + 1 + (d2+1)/2, max(d1, d2));
		par[p2] = p1;
		return true;
	}
	return false;
}

int st, hi, curV;
void dfs(int u, int depth, int p){
	par[u] = curV;
	if (depth > hi){
		hi = max(hi, depth);
		st = u;
	}
	for (int v : adj[u]){
		if (v != p){
			dfs(v, depth + 1, u);
		}
	}
}

int findDiameter(int p){
	hi = -1;
	dfs(p, 0, -1);
	hi = -1;
	dfs(st, 0, -1);
	return hi;
}

int main(){
	std::ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);

	int n, m, q;
	cin >> n >> m >> q;
	for (int i = 0; i < m; i++){
		int a, b;
		cin >> a >> b; a--; b--;
		adj[a].push_back(b);
		adj[b].push_back(a);
	}
	par.assign(n, -1);
	diam.assign(n, 0);
	for (int i = 0; i < n; i++){
		if (par[i] == -1){
			curV = i;
			int d = findDiameter(i);
			diam[i] = d;
		}
	}
	for (int i = 0; i < q; i++){
		int type; cin >> type;
		if (type == 1){
			int u; cin >> u; u--;
			cout << diam[find(u)] << "\n";
		} else {
			int u, v; cin >> u >> v; u--; v--;
			merge(u, v);
		}
	}

	return 0;
}


#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int MAXN = 30100;

vi adj[MAXN];
vi par, diam;
int dist[MAXN];

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

bool merge(int x, int y){
	int p1 = find(x), p2 = find(y);
	if (p1 != p2){
		int d1 = diam[p1], d2 = diam[p2];
		diam[p1] = max((d1+1)/2 + 1 + (d2+1)/2, max(d1, d2));
		par[p2] = p1;
		return true;
	}
	return false;
}

int findDiameter(int p){
	par[p] = p;
	memset(dist, 1, sizeof dist);
	queue<int> q; q.push(p); dist[p] = 0;
	int st, hi = -1;
	while (!q.empty()){
		int u = q.front(); q.pop();
		if (dist[u] > hi){
			hi = dist[u];
			st = u;
		}
		for (int v : adj[u]){
			if (par[v] == -1){
				par[v] = p;
				dist[v] = 1 + dist[u];
				q.push(v);
			}
		}
	}
	hi = -1;
	memset(dist, 1, sizeof dist);
	q.push(st); dist[st] = 0;
	while (!q.empty()){
		int u = q.front(); q.pop();
		if (dist[u] > hi){
			hi = dist[u];
		}
		for (int v : adj[u]){
			if (dist[v] == -1){
				dist[v] = 1 + dist[u];
				q.push(v);
			}
		}
	}
	return hi;
}

int main(){
	std::ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);

	int n, m, q;
	cin >> n >> m >> q;
	for (int i = 0; i < m; i++){
		int a, b;
		cin >> a >> b; a--; b--;
		adj[a].push_back(b);
		adj[b].push_back(a);
	}
	par.assign(n, -1);
	diam.assign(n, 0);
	for (int i = 0; i < n; i++){
		if (par[i] == -1){
			int d = findDiameter(i);
			diam[i] = d;
		}
	}

	for (int i = 0; i < q; i++){
		int type; cin >> type;
		if (type == 1){
			int u; cin >> u; u--;
			cout << diam[find(u)] << "\n";
		} else {
			int u, v; cin >> u >> v; u--; v--;
			merge(u, v);
		}
	}

	return 0;
}


#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int MAXN = 300100;

vi adj[MAXN];
vi par, diam;
int dist[MAXN];

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

bool merge(int x, int y){
	int p1 = find(x), p2 = find(y);
	if (p1 != p2){
		int d1 = diam[p1], d2 = diam[p2];
		diam[p1] = max((d1+1)/2 + 1 + (d2+1)/2, max(d1, d2));
		par[p2] = p1;
		return true;
	}
	return false;
}

int findDiameter(int p){
	par[p] = p;
	memset(dist, -1, sizeof dist);
	queue<int> q; q.push(p); dist[p] = 0;
	int st, hi = -1;
	while (!q.empty()){
		int u = q.front(); q.pop();
		if (dist[u] > hi){
			hi = dist[u];
			st = u;
		}
		for (int v : adj[u]){
			if (par[v] == -1){
				par[v] = p;
				dist[v] = 1 + dist[u];
				q.push(v);
			}
		}
	}
	hi = -1;
	memset(dist, -1, sizeof dist);
	q.push(st); dist[st] = 0;
	while (!q.empty()){
		int u = q.front(); q.pop();
		if (dist[u] > hi){
			hi = dist[u];
		}
		for (int v : adj[u]){
			if (dist[v] == -1){
				dist[v] = 1 + dist[u];
				q.push(v);
			}
		}
	}
	return hi;
}

int main(){
	std::ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);

	int n, m, q;
	cin >> n >> m >> q;
	for (int i = 0; i < m; i++){
		int a, b;
		cin >> a >> b; a--; b--;
		adj[a].push_back(b);
		adj[b].push_back(a);
	}
	par.assign(n, -1);
	diam.assign(n, 0);
	for (int i = 0; i < n; i++){
		if (par[i] == -1){
			int d = findDiameter(i);
			diam[i] = d;
		}
	}
	for (int i = 0; i < q; i++){
		int type; cin >> type;
		if (type == 1){
			int u; cin >> u; u--;
			cout << diam[find(u)] << "\n";
		} else {
			int u, v; cin >> u >> v; u--; v--;
			merge(u, v);
		}
	}

	return 0;
}


#include<bits/stdc++.h>
using namespace std;
// f**k time limit :/
#define ll long long int
const int maxN=3e5+6;
ll n,m,q,masir[maxN],ghotr[maxN],jad[maxN];
vector<ll>g[maxN];
bool mark[maxN];

// thank you soroosh :D
void input(){
    cin>>n>>m>>q;
    for(ll i=0;i<m;i++){
        ll x,y;
        scanf("%d%d",&x,&y);
        g[x].push_back(y);
        g[y].push_back(x);
    }
}

// thank you soroosh :D
void dfs(ll v,ll p,ll gp){
    mark[v]=true;
    jad[v]=gp;
    for(ll i=0;i<g[v].size();i++)
	if(!mark[g[v][i]])
		dfs(g[v][i],v,gp);
for(int i=0;i<g[v].size();i++){
    ll u=g[v][i];
    if(u!=p){
        ghotr[v]=max(ghotr[v],max(ghotr[u],masir[v]+masir[u]+1));
        masir[v]=max(masir[v],masir[u]+1);
	}
}
}

// thank you soroosh :D
ll find_jad(ll x){
    if(jad[x]==x)
        return x;
    return jad[x]=find_jad(jad[x]);
}

void union_jad(ll a,ll b){
    jad[b]=a;

    ghotr[a]=max(max(ghotr[a],ghotr[b]),(ll)(ceil((double)ghotr[a]/2)+ceil((double)ghotr[b]/2)+1));
}

// thank you soroosh :D for union find
void make_mark(){
    for(ll v=1;v<=n;v++)
        if(!mark[v])
            dfs(v,v,v);
}

void show(){
    for(ll i=0;i<q;i++){
        ll w,x,y;
        scanf("%d%d",&w,&x);
        if(w==2){
            scanf("%d",&y);
            x=find_jad(x);
            y=find_jad(y);
            if(x!=y)
                union_jad(find_jad(x),find_jad(y));
        }
        else
            printf("%d\n",ghotr[find_jad(x)]);
    }
}
int main(){
    input();
    make_mark();
    show();
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define ll int
const int maxN=3e5+6;
ll n,m,q,masir[maxN],ghotr[maxN],jad[maxN];
vector<ll>g[maxN];
bool mark[maxN];

// thank you soroosh :D
void input(){
    cin>>n>>m>>q;
    for(ll i=0;i<m;i++){
        ll x,y;
        cin>>x>>y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
}

// thank you soroosh :D
void dfs(ll v,ll p,ll gp){
    mark[v]=true;
    jad[v]=gp;
    for(ll i=0;i<g[v].size();i++)
	if(!mark[g[v][i]])
		dfs(g[v][i],v,gp);
for(int i=0;i<g[v].size();i++){
    ll u=g[v][i];
    if(u!=p){
        ghotr[v]=max(ghotr[v],max(ghotr[u],masir[v]+masir[u]+1));
        masir[v]=max(masir[v],masir[u]+1);
	}
}
}

// thank you soroosh :D
ll find_jad(ll x){
    if(jad[x]==x)
        return x;
    jad[x]= find_jad(jad[x]);
    return jad[x];
}

void union_jad(ll a,ll b){
    jad[b]=a;

    ghotr[a]=max(max(ghotr[a],ghotr[b]),(ll)(ceil((double)ghotr[a]/2)+ceil((double)ghotr[b]/2)+1));
}

// thank you soroosh :D for union find
void make_mark(){
    for(ll v=1;v<=n;v++)
        if(!mark[v])
            dfs(v,v,v);
}

void show(){
    for(ll i=0;i<q;i++){
        ll w,x,y;
        cin>>w>>x;
        if(w==2){
            cin>>y;
            x=find_jad(x);
            y=find_jad(y);
            if(x!=y)
                union_jad(find_jad(x),find_jad(y));
        }
        else
            cout<<ghotr[find_jad(x)]<<'\n';
    }
}
int main(){
    ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    input();
    make_mark();
    show();
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define ll long long int
const int maxN=3e5+300;
ll n,m,q,masir[maxN],ghotr[maxN],jad[maxN];
vector<ll>g[maxN];
bool mark[maxN];

// thank you soroosh :D
void input(){
    cin>>n>>m>>q;
    for(ll i=0;i<m;i++){
        ll x,y;
        cin>>x>>y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
}

// thank you soroosh :D
void dfs(ll v,ll p,ll gp){
    mark[v]=true;
    jad[v]=gp;
    for(ll i=0;i<g[v].size();i++)
	if(!mark[g[v][i]])
		dfs(g[v][i],v,gp);
for(int i=0;i<g[v].size();i++){
    ll u=g[v][i];
    if(u!=p){
        ghotr[v]=max(ghotr[v],max(ghotr[u],masir[v]+masir[u]+1));
        masir[v]=max(masir[v],masir[u]+1);
	}
}
}

// thank you soroosh :D
ll find_jad(ll x){
    if(jad[x]==x)
        return x;
    jad[x]= find_jad(jad[x]);
    return jad[x];
}

void union_jad(ll a,ll b){
    jad[b]=a;

    ghotr[a]=max(max(ghotr[a],ghotr[b]),(ll)(ceil((double)ghotr[a]/2)+ceil((double)ghotr[b]/2)+1));
}

// thank you soroosh :D for union find
void make_mark(){
    for(int v=1;v<=n;v++)
        if(!mark[v])
            dfs(v,v,v);
}

void show(){
    for(ll i=0;i<q;i++){
        ll w,x,y;
        cin>>w>>x;
        if(w==2){
            cin>>y;
            x=find_jad(x);
            y=find_jad(y);
            if(x!=y)
                union_jad(x,y);
        }
        else
            cout<<ghotr[find_jad(x)]<<'\n';
    }
}
int main(){
    input();
    make_mark();
    show();
}


#include<bits/stdc++.h>
using namespace std;
#define ll long long int
const int maxN=3e5+300;
ll n,m,q,masir[maxN],ghotr[maxN],jad[maxN];
vector<ll>g[maxN];
bool mark[maxN];

// thank you soroosh :D
void input(){
    cin>>n>>m>>q;
    for(ll i=0;i<m;i++){
        ll x,y;
        cin>>x>>y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
}

// thank you soroosh :D
void dfs(ll v,ll p,ll gp){
    mark[v]=true;
    jad[v]=gp;
    for(ll i=0;i<g[v].size();i++)
	if(!mark[g[v][i]])
		dfs(g[v][i],v,gp);
for(int i=0;i<g[v].size();i++){
    ll u=g[v][i];
    if(u!=p){
        ghotr[v]=max(ghotr[v],max(ghotr[u],masir[v]+masir[u]+1));
        masir[v]=max(masir[v],masir[u]+1);
	}
}
}

// thank you soroosh :D
ll find_jad(ll x){
    if(jad[x]==x)
        return x;
    jad[x]= find_jad(jad[x]);
    return jad[x];
}

void union_jad(ll a,ll b){
    jad[b]=a;

    ghotr[a]=max(max(ghotr[a],ghotr[b]),(ll)(ceil((double)ghotr[a]/2)+ceil((double)ghotr[b]/2)+1));
}

// thank you soroosh :D for union find
void make_mark(){
    for(int v=1;v<=n;v++)
        if(!mark[v])
            dfs(v,v,v);
}

void show(){
    for(ll i=0;i<q;i++){
        ll w,x,y;
        cin>>w>>x;
        if(w==2){
            cin>>y;
            x=find_jad(x);
            y=find_jad(y);
            if(x!=y)
                union_jad(x,y);
        }
        else
            cout<<ghotr[find_jad(x)]<<endl;
    }
}
int main(){
    input();
    make_mark();
    show();
}


#include<bits/stdc++.h>
using namespace std;
#define ll long long int
const int maxN=3e5+300;
ll n,m,q,masir[maxN],ghotr[maxN],jad[maxN];
vector<ll>g[maxN];
bool mark[maxN];

void input(){
    cin>>n>>m>>q;
    for(ll i=0;i<m;i++){
        ll x,y;
        scanf("%d%d",&x,&y);
        g[x].push_back(y);
        g[y].push_back(x);
    }
}

void dfs(ll v,ll p,ll gp){
    mark[v]=true;
    jad[v]=gp;
    for(ll i=0;i<g[v].size();i++)
	if(!mark[g[v][i]])
		dfs(g[v][i],v,gp);
for(ll i=0;i<g[v].size();i++){
    ll u=g[v][i];
    if(u!=p){
        ghotr[v]=max(ghotr[v],max(ghotr[u],masir[v]+masir[u]+1));
        masir[v]=max(masir[v],masir[u]+1);
	}
}
}

ll find_jad(ll x){
    if(jad[x]==x)
        return x;
    return jad[x]= find_jad(jad[x]);
}

void union_jad(ll a,ll b){
    jad[b]=a;
    ghotr[a]=max(max(ghotr[a],ghotr[b]),(ll)(ceil((double)ghotr[a]/2)+ceil((double)ghotr[b]/2)+1));
}

// thank you soroosh :D for union find
void make_mark(){
    for(ll v=1;v<=n;v++)
        if(!mark[v])
            dfs(v,v,v);
}

void show(){
    for(ll i=0;i<q;i++){
        ll w,x,y;
        cin>>w>>x;
        if(w==2){
            cin>>y;
            x=find_jad(x);
            y=find_jad(y);
            if(x!=y)
                union_jad(x,y);
        }
        else
            cout<<ghotr[find_jad(x)]<<"\n";
    }
}
int main(){
    input();
    make_mark();
    show();
}


#include<bits/stdc++.h>
using namespace std;
#define ll long long int
const int maxN=3e5+300;
ll n,m,q,masir[maxN],ghotr[maxN],jad[maxN];
vector<ll>g[maxN];
bool mark[maxN];

// thank you soroosh :D
void input(){
    cin>>n>>m>>q;
    for(ll i=0;i<m;i++){
        ll x,y;
        cin>>x>>y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
}

// thank you soroosh :D
void dfs(ll v,ll p,ll gp){
    mark[v]=true;
    jad[v]=gp;
    for(ll i=0;i<g[v].size();i++)
	if(!mark[g[v][i]])
		dfs(g[v][i],v,gp);
for(int i=0;i<g[v].size();i++){
    ll u=g[v][i];
    if(u!=p){
        ghotr[v]=max(ghotr[v],max(ghotr[u],masir[v]+masir[u]+1));
        masir[v]=max(masir[v],masir[u]+1);
	}
}
}

// thank you soroosh :D
ll find_jad(ll x){
    if(jad[x]==x)
        return x;
    jad[x]= find_jad(jad[x]);
    return jad[x];
}

void union_jad(ll a,ll b){
    jad[b]=a;

    ghotr[a]=max(max(ghotr[a],ghotr[b]),(ll)(ceil((double)ghotr[a]/2)+ceil((double)ghotr[b]/2)+1));
}

// thank you soroosh :D for union find
void make_mark(){
    for(int v=1;v<=n;v++)
        if(!mark[v])
            dfs(v,v,v);
}

void show(){
    for(ll i=0;i<q;i++){
        ll w,x,y;
        cin>>w>>x;
        if(w==2){
            cin>>y;
            x=find_jad(x);
            y=find_jad(y);
            if(x!=y)
                union_jad(x,y);
        }
        else
            cout<<ghotr[find_jad(x)];
    }
}
int main(){
    input();
    make_mark();
    show();
}


#include<bits/stdc++.h>
using namespace std;
#define ll long long int
const int maxN=3e5+300;
ll n,m,q,masir[maxN],ghotr[maxN],jad[maxN];
vector<ll>g[maxN];
bool mark[maxN];
void input(){
    cin>>n>>m>>q;
    for(ll i=0;i<m;i++){
        ll x,y;
        cin>>x>>y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
}

void dfs(ll v,ll p,ll gp){
    mark[v]=true;
    jad[v]=gp;
    for(ll i=0;i<g[v].size();i++)
	if(!mark[g[v][i]])
		dfs(g[v][i],v,gp);
for(int i=0;i<g[v].size();i++){
    ll u=g[v][i];
    if(u!=p){
        ghotr[v]=max(ghotr[v],max(ghotr[u],masir[v]+masir[u]+1));
        masir[v]=max(masir[v],masir[u]+1);
	}
}
}

ll find_jad(ll x){
    if(jad[x]==x)
        return x;
    jad[x]= find_jad(jad[x]);
    return jad[x];
}

void union_jad(ll a,ll b){
    jad[b]=a;

    ghotr[a]=max(max(ghotr[a],ghotr[b]),(ll)(ceil((double)ghotr[a]/2)+ceil((double)ghotr[b]/2)+1));
}

void make_mark(){
    for(int v=1;v<=n;v++)
        if(!mark[v])
            dfs(v,v,v);
}

void show(){
    for(ll i=0;i<q;i++){
        ll w,x,y;
        cin>>w>>x;
        if(w==2){
            cin>>y;
            x=find_jad(x);
            y=find_jad(y);
            if(x!=y)
                union_jad(x,y);
        }
        else
            cout<<ghotr[find_jad(x)];
    }
}
int main(){
    input();
    make_mark();
    show();
}


#include<bits/stdc++.h>
using namespace std;
#define ll int
const int maxN=3e5+6;
ll n,m,q,masir[maxN],ghotr[maxN],jad[maxN];
vector<ll>g[maxN];
bool mark[maxN];

void input(){
    cin>>n>>m>>q;
    for(ll i=0;i<m;i++){
        ll x,y;
        cin>>x>>y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
}

void dfs(ll v,ll p,ll gp){
    mark[v]=true;
    jad[v]=gp;
    for(ll i=0;i<g[v].size();i++)
	if(!mark[g[v][i]])
		dfs(g[v][i],v,gp);
for(int i=0;i<g[v].size();i++){
    ll u=g[v][i];
    if(u!=p){
        ghotr[v]=max(ghotr[v],max(ghotr[u],masir[v]+masir[u]+1));
        masir[v]=max(masir[v],masir[u]+1);
	}
}
}

// thank you soroosh :D
ll find_jad(ll x){
    if(jad[x]==x)
        return x;
    jad[x]= find_jad(jad[x]);
    return jad[x];
}

void union_jad(ll a,ll b){
    jad[b]=a;

    ghotr[a]=max(max(ghotr[a],ghotr[b]),(ll)(ceil((double)ghotr[a]/2)+ceil((double)ghotr[b]/2)+1));
}

void make_mark(){
    for(ll v=1;v<=n;v++)
        if(!mark[v])
            dfs(v,v,v);
}

void show(){
    for(ll i=0;i<q;i++){
        ll w,x,y;
        cin>>w>>x;
        if(w==2){
            cin>>y;
            x=find_jad(x);
            y=find_jad(y);
            if(x!=y)
                union_jad(find_jad(x),find_jad(y));
        }
        else
            cout<<ghotr[find_jad(x)]<<'\n';
    }
}
int main(){
    ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    input();
    make_mark();
    show();
    return 0;
}


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

using namespace std;

const int MAXSIZE = 300010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int N;
vector < int > V[MAXSIZE];
int maxL=0,last=0;

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller
void Union(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
}
void Init(){
    memset(rank1, 0, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

void dfs(int v,int path,int p) {

    if(path>maxL)
    {
        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, v);
    }
}

void solve(){

    int m,q;
    cin>>N>>m>>q;

    Init();

    for(int i=0;i<m;i++){
        int p,q;
        cin>>p>>q;
        p--,q--;
        if(FindSet(p)!=FindSet(q)) {
            Union(p, q);
        }
        V[p].push_back(q);
        V[q].push_back(p);
    }

    int diameter[N];
    memset(diameter,-1, sizeof(diameter));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(diameter[setIbelongs]==-1){
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }

    }

    int x,y,p;

    while(q--){

        cin>>p>>x;
        x--;
        if(p==1){
            cout<<diameter[FindSet(x)]<<endl;
        }
        else {

            cin>>y;
            y--;
            int setXbelongs = FindSet(x);
            int setYbelongs = FindSet(y);
            int diameteXbelongs=diameter[setXbelongs];
            int diameterYbelongs=diameter[setYbelongs];
            if (setXbelongs != setYbelongs) {
                Union(setXbelongs, setYbelongs);
                //because center minimizes randomness
                diameter[FindSet(setXbelongs)] = max(
                        (double)max(diameteXbelongs,diameterYbelongs),
                        ceil(diameteXbelongs/2.0)+ ceil(diameterYbelongs/2.0)+ 1);

            }

        }
    }
}

int main(){
    Init();
    solve();
}


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

using namespace std;

const int MAXSIZE = 300010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int visited[MAXSIZE];
int diameter[MAXSIZE];
int N;
vector < int > V[MAXSIZE];
int maxL=0,last=0;

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller
void Union(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
}

void Union1(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
    diameter[FindSet(x)] = max(
            (double) max(diameter[x], diameter[y]),
            ceil(diameter[x] / 2.0) + ceil(diameter[y] / 2.0) + 1);
}

void Init(){
    memset(rank1, 0, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

void dfs(int v,int path,int p) {

    if(path>maxL) {
        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, v);
    }
}

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

void solve(){

    int m,q;
//    cin>>N>>m>>q;
    N=nextInt();
    m=nextInt();
    q=nextInt();

    Init();

    for(int i=0;i<m;i++){
        int p,q;
        p=nextInt();
        q=p=nextInt();
//        cin>>p>>q;
        p--,q--;
//        if(FindSet(p)!=FindSet(q)) {
        Union(p, q);
        V[p].push_back(q);
        V[q].push_back(p);
    }

    memset(diameter,-1, sizeof(diameter));
    memset(visited,0, sizeof(visited));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(!visited[setIbelongs]){
            visited[setIbelongs]=1;
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }
    }

    int x,y,p;

    while(q--){
        p=nextInt();
        x=nextInt();
//        cin>>p>>x;
        x--;
        if(p==1){
            printf("%d\n", diameter[FindSet(x)]);
//            cout<<diameter[FindSet(x)]<<endl;
        }
        else {
            y=nextInt();
//            cin>>y;
            y--;
            Union1(x,y);

        }
    }
}

int main(){
    Init();
    solve();
}


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

using namespace std;

const int MAXSIZE = 300010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int visited[MAXSIZE];
int N;
vector < int > V[MAXSIZE];
int maxL=0,last=0;

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller
void Union(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
}
void Init(){
    memset(rank1, 0, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

void dfs(int v,int path,int p) {

    visited[v]=1;
    if(path>maxL) {

        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, v);
    }
}

void solve(){

    int m,q;
    cin>>N>>m>>q;

    Init();

    for(int i=0;i<m;i++){
        int p,q;
        cin>>p>>q;
        p--,q--;
        if(FindSet(p)!=FindSet(q)) {
            Union(p, q);
        }
        V[p].push_back(q);
        V[q].push_back(p);
    }

    int diameter[N];
    memset(diameter,-1, sizeof(diameter));
    memset(visited,0, sizeof(visited));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(!visited[setIbelongs]){
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }

    }

    int x,y,p;

    while(q--){

        cin>>p>>x;
        x--;
        if(p==1){
            cout<<diameter[FindSet(x)]<<endl;
        }
        else {

            cin>>y;
            y--;
            int setXbelongs = FindSet(x);
            int setYbelongs = FindSet(y);
            int diameteXbelongs=diameter[setXbelongs];
            int diameterYbelongs=diameter[setYbelongs];
            if (setXbelongs != setYbelongs) {
                Union(setXbelongs, setYbelongs);
                //because center minimizes randomness
                diameter[FindSet(setXbelongs)] = max(
                        (double)max(diameteXbelongs,diameterYbelongs),
                        ceil(diameteXbelongs/2.0)+ ceil(diameterYbelongs/2.0)+ 1);

            }

        }
    }
}

int main(){
    Init();
    solve();
}


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

using namespace std;

const int MAXSIZE = 300010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int visited[MAXSIZE];
int diameter[MAXSIZE];
int N;
vector < int > V[MAXSIZE];
int maxL=0,last=0;

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller

//try by size
void Union(int x, int y) {
    x = FindSet(x);
    y = FindSet(y);
    if (rank1[x] > rank1[y]) swap(x, y);
    rank1[y] += rank1[x];
    parent[x] = y;
}

//void Union(int root1, int root2){
//    int x = FindSet(root1), y = FindSet(root2);
//    if( x == y ) return ;
//    if(rank1[x] > rank1[y] ) parent[y] = x;
//    else{
//        parent[x] = y;
//        if( rank1[x] == rank1[y] ) ++rank1[y];
//    }
//}

void Union1(int x, int y){
    x = FindSet(x);
    y = FindSet(y);
    if (rank1[x] > rank1[y]) swap(x, y);
    rank1[y] += rank1[x];
    parent[x] = y;
    diameter[FindSet(x)] = max(
            (double) max(diameter[x], diameter[y]),
            ceil(diameter[x] / 2.0) + ceil(diameter[y] / 2.0) + 1);
}

void Init(){
    memset(rank1, 1, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

void dfs(int v,int path,int p) {

    visited[v]=1;
    if(path>maxL) {

        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, v);
    }
}

void solve(){

    int m,q;
    cin>>N>>m>>q;

    Init();

    for(int i=0;i<m;i++){
        int p,q;
        cin>>p>>q;
        p--,q--;
//        if(FindSet(p)!=FindSet(q)) {
        Union(p, q);
//        }
        V[p].push_back(q);
        V[q].push_back(p);
    }

    memset(diameter,-1, sizeof(diameter));
    memset(visited,0, sizeof(visited));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(!visited[setIbelongs]){
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }
    }

    int x,y,p;

    while(q--){

        cin>>p>>x;
        x--;
        if(p==1){
            cout<<diameter[FindSet(x)]<<endl;
        }
        else {

            cin>>y;
            y--;
            Union1(x,y);

        }
    }
}

int main(){
    Init();
    solve();
}


#include <algorithm>
#include <iostream>
#include <queue>
#include <set>
#include <cmath>

using namespace std;

const int MAXSIZE = 500010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int  degree[MAXSIZE];
queue <int> q;
int  maxlevel = 0; // Level of center of graph
int  level[MAXSIZE]; // Level of node
int N;
set<int> c;

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller
void Union(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
}
void Init(){
    memset(rank1, 0, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

int visited[10005],dist[10005];
vector < int > V[10005];
int maxL=0,last=0;
void dfs(int v,int path,int p) {

    if(path>maxL)
    {
        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, p);
    }
}

void solve(){

    int m,q;
    cin>>N>>m>>q;

    Init();

    for(int i=0;i<m;i++){
        int p,q;
        cin>>p>>q;
        p--,q--;
        if(FindSet(p)!=FindSet(q)) {
            Union(p, q);
        }
        V[p].push_back(q);
        V[q].push_back(p);
    }

    int diameter[N];
    memset(diameter,-1, sizeof(diameter));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(diameter[setIbelongs]==-1){
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }

    }

    int x,y,p;

    while(q--){

        cin>>p>>x;
        x--;
        if(p==1){
            cout<<diameter[FindSet(x)]<<endl;
        }
        else {

            cin>>y;
            y--;
            int setXbelongs = FindSet(x);
            int setYbelongs = FindSet(y);
            int diameteXbelongs=diameter[setXbelongs];
            int diameterYbelongs=diameter[setYbelongs];
            if (setXbelongs != setYbelongs) {
                Union(setXbelongs, setYbelongs);
                //because center minimizes randomness
                diameter[FindSet(setXbelongs)] = max(
                        (double)max(diameteXbelongs,diameterYbelongs),
                        ceil(diameteXbelongs/2.0)+ ceil(diameterYbelongs/2.0)+ 1);

            }

        }
    }
}

int main(){
    Init();
    solve();
}


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

using namespace std;

const int MAXSIZE = 300010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int visited[MAXSIZE];
int N;
vector < int > V[MAXSIZE];
int maxL=0,last=0;

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller
void Union(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
}
void Init(){
    memset(rank1, 0, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

void dfs(int v,int path,int p) {

    visited[v]=1;
    if(path>maxL) {

        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, v);
    }
}

void solve(){

    int m,q;
    cin>>N>>m>>q;

    Init();

    for(int i=0;i<m;i++){
        int p,q;
        cin>>p>>q;
        p--,q--;
        if(FindSet(p)!=FindSet(q)) {
            Union(p, q);
        }
        V[p].push_back(q);
        V[q].push_back(p);
    }

    int diameter[N];
    memset(diameter,-1, sizeof(diameter));
    memset(visited,0, sizeof(visited));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(!visited[i]){
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }

    }

    int x,y,p;

    while(q--){

        cin>>p>>x;
        x--;
        if(p==1){
            cout<<diameter[FindSet(x)]<<endl;
        }
        else {

            cin>>y;
            y--;
            int setXbelongs = FindSet(x);
            int setYbelongs = FindSet(y);
            int diameteXbelongs=diameter[setXbelongs];
            int diameterYbelongs=diameter[setYbelongs];
            if (setXbelongs != setYbelongs) {
                Union(setXbelongs, setYbelongs);
                //because center minimizes randomness
                diameter[FindSet(setXbelongs)] = max(
                        (double)max(diameteXbelongs,diameterYbelongs),
                        ceil(diameteXbelongs/2.0)+ ceil(diameterYbelongs/2.0)+ 1);

            }

        }
    }
}

int main(){
    Init();
    solve();
}


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

using namespace std;

const int MAXSIZE = 300010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int visited[MAXSIZE];
int diameter[MAXSIZE];
int N;
vector < int > V[MAXSIZE];
int maxL=0,last=0;

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller

//try by size
void Union(int x, int y) {
    x = FindSet(x);
    y = FindSet(y);
    if (rank1[x] > rank1[y]) swap(x, y);
    rank1[y] += rank1[x];
    parent[x] = y;
}

//void Union(int root1, int root2){
//    int x = FindSet(root1), y = FindSet(root2);
//    if( x == y ) return ;
//    if(rank1[x] > rank1[y] ) parent[y] = x;
//    else{
//        parent[x] = y;
//        if( rank1[x] == rank1[y] ) ++rank1[y];
//    }
//}

void Union1(int x, int y){
    x = FindSet(x);
    y = FindSet(y);
    if (x == y) return;
    if (rank1[x] > rank1[y]) swap(x, y);
    rank1[y] += rank1[x];
    parent[x] = y;
    diameter[FindSet(x)] = max(
            (double) max(diameter[x], diameter[y]),
            ceil(diameter[x] / 2.0) + ceil(diameter[y] / 2.0) + 1);
}

void Init(){
    memset(rank1, 1, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

void dfs(int v,int path,int p) {

    visited[v]=1;
    if(path>maxL) {

        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, v);
    }
}

void solve(){

    int m,q;
    cin>>N>>m>>q;

    Init();

    for(int i=0;i<m;i++){
        int p,q;
        cin>>p>>q;
        p--,q--;
//        if(FindSet(p)!=FindSet(q)) {
        Union(p, q);
//        }
        V[p].push_back(q);
        V[q].push_back(p);
    }

    memset(diameter,-1, sizeof(diameter));
    memset(visited,0, sizeof(visited));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(!visited[setIbelongs]){
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }
    }

    int x,y,p;

    while(q--){

        cin>>p>>x;
        x--;
        if(p==1){
            cout<<diameter[FindSet(x)]<<endl;
        }
        else {

            cin>>y;
            y--;
            Union1(x,y);

        }
    }
}

int main(){
    Init();
    solve();
}


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

using namespace std;

const int MAXSIZE = 300010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int N;
vector < int > V[MAXSIZE];
int maxL=0,last=0;

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

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller
void Union(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
}
void Init(){
    memset(rank1, 0, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

void dfs(int v,int path,int p) {

    if(path>maxL)
    {
        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, v);
    }
}

void solve(){

    int m,q;
//    cin>>N>>m>>q;
    N=nextInt();
    m=nextInt();
    q=nextInt();

    Init();

    for(int i=0;i<m;i++){
        int p,q;
//        cin>>p>>q;
        p=nextInt();
        q=nextInt();
        p--,q--;
        if(FindSet(p)!=FindSet(q)) {
            Union(p, q);
        }
        V[p].push_back(q);
        V[q].push_back(p);
    }

    int diameter[N];
    memset(diameter,-1, sizeof(diameter));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(diameter[setIbelongs]==-1){
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }

    }

    int x,y,p;

    while(q--){

//        cin>>p>>x;
        p=nextInt();
        x=nextInt();
        x--;
        if(p==1){
            printf("%d\n", diameter[FindSet(x)]);
//            cout<<diameter[FindSet(x)]<<endl;
        }
        else {

            y=nextInt();
//            cin>>y;
            y--;
            int setXbelongs = FindSet(x);
            int setYbelongs = FindSet(y);
            int diameteXbelongs=diameter[setXbelongs];
            int diameterYbelongs=diameter[setYbelongs];
            if (setXbelongs != setYbelongs) {
                Union(setXbelongs, setYbelongs);
                //because center minimizes randomness
                diameter[FindSet(setXbelongs)] = max(
                        (double)max(diameteXbelongs,diameterYbelongs),
                        ceil(diameteXbelongs/2.0)+ ceil(diameterYbelongs/2.0)+ 1);

            }

        }
    }
}

int main(){
    Init();
    solve();
}


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

using namespace std;

const int MAXSIZE = 300010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int visited[MAXSIZE];
int N;
vector < int > V[MAXSIZE];
int maxL=0,last=0;

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller
void Union(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
}
void Init(){
    memset(rank1, 0, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

void dfs(int v,int path,int p) {

    visited[v]=1;
    if(path>maxL) {

        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, v);
    }
}

void solve(){

    int m,q;
    cin>>N>>m>>q;

    Init();

    for(int i=0;i<m;i++){
        int p,q;
        cin>>p>>q;
        p--,q--;
//        if(FindSet(p)!=FindSet(q)) {
        Union(p, q);
//        }
        V[p].push_back(q);
        V[q].push_back(p);
    }

    int diameter[N];
    memset(diameter,-1, sizeof(diameter));
    memset(visited,0, sizeof(visited));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(!visited[setIbelongs]){
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }

    }

    int x,y,p;

    while(q--){

        cin>>p>>x;
        x--;
        if(p==1){
            cout<<diameter[FindSet(x)]<<endl;
        }
        else {

            cin>>y;
            y--;
            int setXbelongs = FindSet(x);
            int setYbelongs = FindSet(y);
            int diameteXbelongs=diameter[setXbelongs];
            int diameterYbelongs=diameter[setYbelongs];
            if (setXbelongs != setYbelongs) {
                //because center minimizes randomness
                //do in O(1)here
                if(rank1[setXbelongs] > rank1[setYbelongs]) {
                    diameter[setXbelongs] = max(
                            (double) max(diameteXbelongs, diameterYbelongs),
                            ceil(diameteXbelongs / 2.0) + ceil(diameterYbelongs / 2.0) + 1);
                }
                else{
                    diameter[setYbelongs] = max(
                            (double) max(diameteXbelongs, diameterYbelongs),
                            ceil(diameteXbelongs / 2.0) + ceil(diameterYbelongs / 2.0) + 1);
                }
                Union(setXbelongs, setYbelongs);
            }

        }
    }
}

int main(){
    Init();
    solve();
}


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

using namespace std;

const int MAXSIZE = 300010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int visited[MAXSIZE];
int diameter[MAXSIZE];
int N;
vector < int > V[MAXSIZE];
int maxL=0,last=0;

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller
void Union(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
}

void Union1(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
    diameter[FindSet(x)] = max(
            (double) max(diameter[x], diameter[y]),
            ceil(diameter[x] / 2.0) + ceil(diameter[y] / 2.0) + 1);
}

void Init(){
    memset(rank1, 0, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

void dfs(int v,int path,int p) {

    if(path>maxL) {
        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, v);
    }
}

void solve(){

    int m,q;
    cin>>N>>m>>q;

    Init();

    for(int i=0;i<m;i++){
        int p,q;
        cin>>p>>q;
        p--,q--;
//        if(FindSet(p)!=FindSet(q)) {
        Union(p, q);
//        }
        V[p].push_back(q);
        V[q].push_back(p);
    }

    memset(diameter,-1, sizeof(diameter));
    memset(visited,0, sizeof(visited));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(!visited[setIbelongs]){
            visited[setIbelongs]=1;
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }
    }

    int x,y,p;

    while(q--){

        cin>>p>>x;
        x--;
        if(p==1){
            cout<<diameter[FindSet(x)]<<endl;
        }
        else {

            cin>>y;
            y--;
            Union1(x,y);

        }
    }
}

int main(){
    Init();
    solve();
}


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

using namespace std;

const int MAXSIZE = 300010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int visited[MAXSIZE];
int diameter[MAXSIZE];
int N;
vector < int > V[MAXSIZE];
int maxL=0,last=0;

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller

//try by size
void Union(int x, int y) {
    x = FindSet(x);
    y = FindSet(y);
    if (rank1[x] > rank1[y]) swap(x, y);
    rank1[y] += rank1[x];
    parent[x] = y;
}

//void Union(int root1, int root2){
//    int x = FindSet(root1), y = FindSet(root2);
//    if( x == y ) return ;
//    if(rank1[x] > rank1[y] ) parent[y] = x;
//    else{
//        parent[x] = y;
//        if( rank1[x] == rank1[y] ) ++rank1[y];
//    }
//}

void Union1(int x, int y){
    x = FindSet(x);
    y = FindSet(y);
    if (rank1[x] > rank1[y]) swap(x, y);
    rank1[y] += rank1[x];
    parent[x] = y;
    diameter[FindSet(x)] = max(
            (double) max(diameter[x], diameter[y]),
            ceil(diameter[x] / 2.0) + ceil(diameter[y] / 2.0) + 1);
}

void Init(){
    memset(rank1, 0, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

void dfs(int v,int path,int p) {

    visited[v]=1;
    if(path>maxL) {

        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, v);
    }
}

void solve(){

    int m,q;
    cin>>N>>m>>q;

    Init();

    for(int i=0;i<m;i++){
        int p,q;
        cin>>p>>q;
        p--,q--;
//        if(FindSet(p)!=FindSet(q)) {
        Union(p, q);
//        }
        V[p].push_back(q);
        V[q].push_back(p);
    }

    memset(diameter,-1, sizeof(diameter));
    memset(visited,0, sizeof(visited));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(!visited[setIbelongs]){
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }
    }

    int x,y,p;

    while(q--){

        cin>>p>>x;
        x--;
        if(p==1){
            cout<<diameter[FindSet(x)]<<endl;
        }
        else {

            cin>>y;
            y--;
            Union1(x,y);

        }
    }
}

int main(){
    Init();
    solve();
}


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

using namespace std;

const int MAXSIZE = 500010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int N;
vector < int > V[10005];
int maxL=0,last=0;

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller
void Union(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
}
void Init(){
    memset(rank1, 0, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

void dfs(int v,int path,int p) {

    if(path>maxL)
    {
        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, p);
    }
}

void solve(){

    int m,q;
    cin>>N>>m>>q;

    Init();

    for(int i=0;i<m;i++){
        int p,q;
        cin>>p>>q;
        p--,q--;
        if(FindSet(p)!=FindSet(q)) {
            Union(p, q);
        }
        V[p].push_back(q);
        V[q].push_back(p);
    }

    int diameter[N];
    memset(diameter,-1, sizeof(diameter));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(diameter[setIbelongs]==-1){
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }

    }

    int x,y,p;

    while(q--){

        cin>>p>>x;
        x--;
        if(p==1){
            cout<<diameter[FindSet(x)]<<endl;
        }
        else {

            cin>>y;
            y--;
            int setXbelongs = FindSet(x);
            int setYbelongs = FindSet(y);
            int diameteXbelongs=diameter[setXbelongs];
            int diameterYbelongs=diameter[setYbelongs];
            if (setXbelongs != setYbelongs) {
                Union(setXbelongs, setYbelongs);
                //because center minimizes randomness
                diameter[FindSet(setXbelongs)] = max(
                        (double)max(diameteXbelongs,diameterYbelongs),
                        ceil(diameteXbelongs/2.0)+ ceil(diameterYbelongs/2.0)+ 1);

            }

        }
    }
}

int main(){
    Init();
    solve();
}


#include <algorithm>
#include <iostream>
#include <queue>
#include <set>
#include <cmath>

using namespace std;

const int MAXSIZE = 500010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int  degree[MAXSIZE];
queue <int> q;
int  maxlevel = 0; // Level of center of graph
int  level[MAXSIZE]; // Level of node
int  g[MAXSIZE][MAXSIZE]; // Adjacency matrix
int N;
set<int> c;

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller
void Union(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
}
void Init(void){
    memset(rank1, 0, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

int visited[10005],dist[10005];
vector < int > V[10005];
int maxL=0,last=0;
void dfs(int v,int path,int p) {

    if(path>maxL)
    {
        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, p);
    }
}

void solve(){

    int m,q;
    cin>>N>>m>>q;

    Init();

    for(int i=0;i<m;i++){
        int p,q;
        cin>>p>>q;
        p--,q--;
        if(FindSet(p)!=FindSet(q)) {
            Union(p, q);
        }
        V[p].push_back(q);
        V[q].push_back(p);
    }

    int diameter[N];
    memset(diameter,-1, sizeof(diameter));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(diameter[setIbelongs]==-1){
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }

    }

    int x,y,p;

    while(q--){

        cin>>p>>x;
        x--;
        if(p==1){
            cout<<diameter[FindSet(x)]<<endl;
        }
        else {

            cin>>y;
            y--;
            int setXbelongs = FindSet(x);
            int setYbelongs = FindSet(y);
            int diameteXbelongs=diameter[setXbelongs];
            int diameterYbelongs=diameter[setYbelongs];
            if (setXbelongs != setYbelongs) {
                Union(setXbelongs, setYbelongs);
                //because center minimizes randomness
                diameter[FindSet(setXbelongs)] = max(
                        (double)max(diameteXbelongs,diameterYbelongs),
                        ceil(diameteXbelongs/2.0)+ ceil(diameterYbelongs/2.0)+ 1);

            }

        }
    }
}

int main(){
    Init();
    solve();
}


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

using namespace std;

const int MAXSIZE = 300010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int visited[MAXSIZE];
int diameter[MAXSIZE];
int N;
vector < int > V[MAXSIZE];
int maxL=0,last=0;

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller
void Union(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
}

void Union1(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
    diameter[FindSet(x)] = max(
            (double) max(diameter[x], diameter[y]),
            ceil(diameter[x] / 2.0) + ceil(diameter[y] / 2.0) + 1);
}

void Init(){
    memset(rank1, 0, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

void dfs(int v,int path,int p) {

    visited[v]=1;
    if(path>maxL) {

        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, v);
    }
}

void solve(){

    int m,q;
    cin>>N>>m>>q;

    Init();

    for(int i=0;i<m;i++){
        int p,q;
        cin>>p>>q;
        p--,q--;
//        if(FindSet(p)!=FindSet(q)) {
        Union(p, q);
//        }
        V[p].push_back(q);
        V[q].push_back(p);
    }

    memset(diameter,-1, sizeof(diameter));
    memset(visited,0, sizeof(visited));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(!visited[setIbelongs]){
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }
    }

    int x,y,p;

    while(q--){

        cin>>p>>x;
        x--;
        if(p==1){
            cout<<diameter[FindSet(x)]<<endl;
        }
        else {

            cin>>y;
            y--;
            Union1(x,y);

        }
    }
}

int main(){
    Init();
    solve();
}


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

using namespace std;

const int MAXSIZE = 300010;
int rank1[MAXSIZE];
int parent[MAXSIZE];
int visited[MAXSIZE];
int N;
vector < int > V[MAXSIZE];
int maxL=0,last=0;

//height of the tree for find operation will be smaller
int FindSet(int x){
    if( x != parent[x] ) parent[x] = FindSet(parent[x]);
    return parent[x];
}
//height of the tree of union operation will be smaller
void Union(int root1, int root2){
    int x = FindSet(root1), y = FindSet(root2);
    if( x == y ) return ;
    if(rank1[x] > rank1[y] ) parent[y] = x;
    else{
        parent[x] = y;
        if( rank1[x] == rank1[y] ) ++rank1[y];
    }
}
void Init(){
    memset(rank1, 0, sizeof(rank1));
    for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
}

void dfs(int v,int path,int p) {

    visited[v]=1;
    if(path>maxL) {

        maxL=path;
        last=v;
    }
    for(int i=0;i<V[v].size();i++) {
        int to = V[v][i];
        if (to != p)  // this check is for undirected graph
            dfs(V[v][i], path + 1, v);
    }
}

void solve(){

    int m,q;
    cin>>N>>m>>q;

    Init();

    for(int i=0;i<m;i++){
        int p,q;
        cin>>p>>q;
        p--,q--;
//        if(FindSet(p)!=FindSet(q)) {
        Union(p, q);
//        }
        V[p].push_back(q);
        V[q].push_back(p);
    }

    int diameter[N];
    memset(diameter,-1, sizeof(diameter));
    memset(visited,0, sizeof(visited));

    for(int i=0;i<N;i++){

        int setIbelongs=FindSet(i);
        if(!visited[setIbelongs]){
            maxL = -1;
            dfs(i,0,-1);
            maxL=-1;
            dfs(last,0,-1);
            diameter[setIbelongs]=maxL;
        }

    }

    int x,y,p;

    while(q--){

        cin>>p>>x;
        x--;
        if(p==1){
            cout<<diameter[FindSet(x)]<<endl;
        }
        else {

            cin>>y;
            y--;
            int setXbelongs = FindSet(x);
            int setYbelongs = FindSet(y);
            int diameteXbelongs=diameter[setXbelongs];
            int diameterYbelongs=diameter[setYbelongs];
            if (setXbelongs != setYbelongs) {
                Union(setXbelongs, setYbelongs);
                //because center minimizes randomness
                diameter[FindSet(setXbelongs)] = max(
                        (double)max(diameteXbelongs,diameterYbelongs),
                        ceil(diameteXbelongs/2.0)+ ceil(diameterYbelongs/2.0)+ 1);

            }

        }
    }
}

int main(){
    Init();
    solve();
}


#include <bits/stdc++.h>

using namespace std;

vector <pair <int, pair <int, int> > > G;
vector <pair <int, int> > Gr[200010];
vector <int> parrent;
vector <int> runk;
int up[200010][20];
int lcost[200010][20];
int timer = 0;
vector <int> tin;
vector <int> tout;
void dfs(int v, int par, int co)
{
    tin[v] = ++timer;
    up[v][0] = par;
    lcost[v][0] = co;
    for (int i = 1; i < 20; i++)
    {
        int vv = up[v][i - 1];
        up[v][i] = up[vv][i - 1];
        lcost[v][i] = max(lcost[v][i - 1], lcost[vv][i - 1]);
    }
    for (auto to : Gr[v])
        if (to.first != par)
            dfs(to.first, v, to.second);
    tout[v] = ++timer;
}
bool is_upper(int low, int up)
{
    return (tin[up] <= tin[low] && tout[up] >= tout[low]);
}
int cost_l (int u, int v)
{
    int ans = 0;
    for (int i = 19; i >= 0; i--)
    {
        int uu = up[u][i];
        if (!is_upper(uu, v))
        {
            ans = max(ans, lcost[u][i]);
            u = uu;
        }
    }
    for (int i = 19; i >= 0; i--)
    {
        int vv = up[v][i];
        if (!is_upper(vv, u))
        {
            ans = max(ans, lcost[v][i]);
            v = vv;
        }
    }
    return ans;
}
int lca(int u, int v)
{
    if (is_upper(v, u))
        return u;
    for (int i = 19; i >= 0; i--)
    {
        int uu = up[u][i];
        if (!is_upper(v, uu))
        {
            u = uu;
        }
    }
    return up[u][0];
}
int find_set(int v)
{
    if (v == parrent[v])
        return v;
    return parrent[v] = find_set(parrent[v]);
}
void union_set(int a, int b)
{
    a = find_set(a);
    b = find_set(b);
    if (runk[a] < runk[b])
        swap(a, b);
    parrent[b] = a;
    runk[a] += b;
}
void make_set(int v)
{
    parrent[v] = v;
    runk[v] = 1;
}
int main()
{
    int n, m;
    cin >> n >> m;
    tin.resize(n + 1);
    tout.resize(n + 1);
    parrent.resize(n + 1);
    runk.resize(n + 1);
    for (int i = 0; i < m; i++)
    {
        int q, q1, c;
        cin >> q >> q1 >> c;
        G.push_back({c, {q, q1}});
    }
    for (int i = 1; i <= n; i++)
    {
        make_set(i);
    }
    int cnt = 0;
    sort(G.begin(), G.end());
    for (int i = 0; i < m; i++)
    {
        int a = G[i].second.first, b = G[i].second.second;
        if (find_set(a) != find_set(b))
        {
            union_set(a, b);
            cnt += G[i].first;
            Gr[a].push_back({b, G[i].first});
            Gr[b].push_back({a, G[i].first});
        }
    }
    dfs(1, 1, 0);
    for (int i = 1; i <= m; i++)
    {
        int acnt = cnt;
        acnt += G[i].first;
        acnt -= cost_l(G[i].second.first, G[i].second.second);
        cout << acnt << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;
#define int long long
vector <pair <int, pair <int, int> > > G;
vector <pair <int, pair <int, int> > > Gdub;
vector <pair <int, int> > Gr[200010];
vector <int> parrent;
vector <int> runk;
int up[200010][20];
int lcost[200010][20];
int timer = 0;
vector <int> tin;
vector <int> tout;
void dfs(int v, int par, int co)
{
    tin[v] = ++timer;
    up[v][0] = par;
    lcost[v][0] = co;
    for (int i = 1; i < 20; i++)
    {
        int vv = up[v][i - 1];
        up[v][i] = up[vv][i - 1];
        lcost[v][i] = max(lcost[v][i - 1], lcost[vv][i - 1]);
    }
    for (auto to : Gr[v])
        if (to.first != par)
            dfs(to.first, v, to.second);
    tout[v] = ++timer;
}
bool is_upper(int low, int up)
{
    return (tin[up] <= tin[low] && tout[up] >= tout[low]);
}
int cost_l (int u, int v)
{
    if (is_upper(v, u))
        return 0;
    int ans = 0;
    for (int i = 19; i >= 0; i--)
    {
        int uu = up[u][i];
        if (!is_upper(v, uu))
        {
            ans = max(ans, lcost[u][i]);
            u = uu;
        }
    }
    return max(ans, lcost[u][0]);
}
int lca(int u, int v)
{
    if (is_upper(v, u))
        return u;
    for (int i = 19; i >= 0; i--)
    {
        int uu = up[u][i];
        if (!is_upper(v, uu))
        {
            u = uu;
        }
    }
    return up[u][0];
}
int find_set(int v)
{
    if (v == parrent[v])
        return v;
    return parrent[v] = find_set(parrent[v]);
}
void union_set(int a, int b)
{
    a = find_set(a);
    b = find_set(b);
    if (runk[a] < runk[b])
        swap(a, b);
    parrent[b] = a;
    runk[a] += b;
}
void make_set(int v)
{
    parrent[v] = v;
    runk[v] = 1;
}
signed main()
{
    int n, m;
    cin >> n >> m;
    tin.resize(n + 1);
    tout.resize(n + 1);
    parrent.resize(n + 1);
    runk.resize(n + 1);
    for (int i = 0; i < m; i++)
    {
        int q, q1, c;
        cin >> q >> q1 >> c;
        G.push_back({c, {q, q1}});
        Gdub.push_back({c, {q, q1}});
    }
    for (int i = 1; i <= n; i++)
    {
        make_set(i);
    }
    int cnt = 0;
    sort(G.begin(), G.end());
    for (int i = 0; i < m; i++)
    {
        int a = G[i].second.first, b = G[i].second.second;
        if (find_set(a) != find_set(b))
        {
            union_set(a, b);
            cnt += G[i].first;
            Gr[a].push_back({b, G[i].first});
            Gr[b].push_back({a, G[i].first});
        }
    }
    dfs(1, 1, 0);
    cout << "------" << endl;
    for (int i = 0; i < m; i++)
    {
        int acnt = cnt;
        acnt += Gdub[i].first;
        acnt -= max(cost_l(Gdub[i].second.first, Gdub[i].second.second), cost_l(Gdub[i].second.second, Gdub[i].second.first));
       // cout << max(cost_l(Gdub[i].second.first, Gdub[i].second.second), cost_l(Gdub[i].second.second, Gdub[i].second.first)) << " " << Gdub[i].second.first << " " << Gdub[i].second.second << endl;
        cout << acnt << endl;
    }
    return 0;
}


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

#define ll long long
ll lcost[211111][20];
ll up[211111][20];
ll timer = 0;
vector <ll> tin;
vector <ll> tout;
vector <vector <pair <ll, ll> > > g;
void dfs(ll v, ll p, ll c)
{
    tin[v] = timer++;
    lcost[v][0] = c;
    up[v][0] = p;
    for (ll i = 1; i < 20; i++)
    {
        ll vv = up[v][i - 1];
        up[v][i] = up[vv][i - 1];
        lcost[v][i] = max(lcost[v][i - 1], lcost[vv][i - 1]);
    }
    for (ll i = 0; i < g[v].size(); i++)
    {
        ll to = g[v][i].first, co = g[v][i].second;
        if (to != p)
        {
            dfs(to, v, co);
        }
    }
    tout[v] = timer++;
}
bool upper(ll low, ll u)
{
    return tin[u] <= tin[low] && tout[u] >= tout[low];
}
ll l_cost(ll v, ll u)
{
    if (upper(v, u))
        return 0;
    ll ans = 0;
    for (ll i = 19; i >= 0; i--)
    {
        ll uu = up[u][i];
        if (!upper(v, uu))
        {
            ans = max(ans, lcost[u][i]);
            u = uu;
        }
    }
    return max(ans, lcost[u][0]);
}
vector <ll> r;
vector <ll> p;
void make_set(ll a)
{
    p[a] = a;
    r[a] = 1;
}
ll f_p(ll a)
{
    if (p[a] == a)
        return a;
    return p[a] = f_p(p[a]);
}
bool un(ll a, ll b)
{
    a = f_p(a);
    b = f_p(b);
    if (a == b)
        return false;
    if (r[a] < r[b])
        swap(a, b);
    r[a] += r[b];
    p[b] = a;
    return true;
}
vector <pair <ll, pair <ll, ll> > > ed;
vector <pair <ll, pair <ll, ll> > > edges;
int main() {
    ll n, m;
    cin >> n >> m;
    tin.resize(n + 1);
    tout.resize(n + 1);
    r.resize(n + 1);
    p.resize(n + 1);
    g.resize(n + 1);
    for (ll i = 1; i <= n; i++)
    {
        make_set(i);
    }
    for (ll i = 0; i < m; i++)
    {
        ll f, t, c;
        cin >> f >> t >> c;
        ed.push_back({c, {f, t}});
        edges.push_back({c, {f, t}});
    }
    long long cost = 0;
    sort(ed.begin(), ed.end());
    for (ll i = 0; i < ed.size(); i++)
    {
        ll f = ed[i].second.first;
        ll t = ed[i].second.second;
        ll c = ed[i].first;
        if (un(f, t))
        {
            g[f].push_back({t, c});
            g[t].push_back({f, c});
            cost += c;
        }
    }
    dfs(1, 1, 0);
    for (ll i = 0; i < edges.size(); i++)
    {
        ll f = edges[i].second.first;
        ll t = edges[i].second.second;
        ll c = edges[i].first;
        ll ans = cost + c - max(l_cost(f, t), l_cost(t, f));
        cout << ans << endl;
    }
}


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

#define ll int
ll lcost[211111][20];
ll up[211111][20];
ll timer = 0;
vector <ll> tin;
vector <ll> tout;
vector <vector <pair <ll, ll> > > g;
void dfs(ll v, ll p, ll c)
{
    tin[v] = timer++;
    lcost[v][0] = c;
    up[v][0] = p;
    for (ll i = 1; i < 20; i++)
    {
        ll vv = up[v][i - 1];
        up[v][i] = up[vv][i - 1];
        lcost[v][i] = max(lcost[v][i - 1], lcost[vv][i - 1]);
    }
    for (ll i = 0; i < g[v].size(); i++)
    {
        ll to = g[v][i].first, co = g[v][i].second;
        if (to != p)
        {
            dfs(to, v, co);
        }
    }
    tout[v] = timer++;
}
bool upper(ll low, ll u)
{
    return tin[u] <= tin[low] && tout[u] >= tout[low];
}
ll l_cost(ll v, ll u)
{
    if (upper(v, u))
        return 0;
    ll ans = 0;
    for (ll i = 19; i >= 0; i--)
    {
        ll uu = up[u][i];
        if (!upper(v, uu))
        {
            ans = max(ans, lcost[u][i]);
            u = uu;
        }
    }
    return max(ans, lcost[u][0]);
}
vector <ll> r;
vector <ll> p;
void make_set(ll a)
{
    p[a] = a;
    r[a] = 1;
}
ll f_p(ll a)
{
    if (p[a] == a)
        return a;
    return p[a] = f_p(p[a]);
}
bool un(ll a, ll b)
{
    a = f_p(a);
    b = f_p(b);
    if (a == b)
        return false;
    if (r[a] < r[b])
        swap(a, b);
    r[a] += r[b];
    p[b] = a;
    return true;
}
vector <pair <ll, pair <ll, ll> > > ed;
vector <pair <ll, pair <ll, ll> > > edges;
int main() {
    ll n, m;
    cin >> n >> m;
    tin.resize(n + 1);
    tout.resize(n + 1);
    r.resize(n + 1);
    p.resize(n + 1);
    g.resize(n + 1);
    for (ll i = 1; i <= n; i++)
    {
        make_set(i);
    }
    for (ll i = 0; i < m; i++)
    {
        ll f, t, c;
        cin >> f >> t >> c;
        ed.push_back({c, {f, t}});
        edges.push_back({c, {f, t}});
    }
    ll cost = 0;
    sort(ed.begin(), ed.end());
    for (ll i = 0; i < ed.size(); i++)
    {
        ll f = ed[i].second.first;
        ll t = ed[i].second.second;
        ll c = ed[i].first;
        if (un(f, t))
        {
            g[f].push_back({t, c});
            g[t].push_back({f, c});
            cost += c;
        }
    }
    dfs(1, 1, 0);
    for (ll i = 0; i < edges.size(); i++)
    {
        ll f = edges[i].second.first;
        ll t = edges[i].second.second;
        ll c = edges[i].first;
        ll ans = cost + c - max(l_cost(f, t), l_cost(t, f));
        cout << ans << endl;
    }
}


#include <bits/stdc++.h>

using namespace std;
vector <pair <long long, pair <long long, long long> > > G;
vector <pair <long long, long long> > Gr[200010];
vector <long long> parrent;
vector <long long> runk;
long long up[200010][20];
long long lcost[200010][20];
long long timer = 0;
vector <long long> tin;
vector <long long> tout;
void dfs(long long v, long long par, long long co)
{
    tin[v] = ++timer;
    up[v][0] = par;
    lcost[v][0] = co;
    for (long long i = 1; i < 20; i++)
    {
        long long vv = up[v][i - 1];
        up[v][i] = up[vv][i - 1];
        lcost[v][i] = max(lcost[v][i - 1], lcost[vv][i - 1]);
    }
    for (auto to : Gr[v])
        if (to.first != par)
            dfs(to.first, v, to.second);
    tout[v] = ++timer;
}
bool is_upper(int low, int up)
{
    return (tin[up] <= tin[low] && tout[up] >= tout[low]);
}
long long cost_l (long long u, long long v)
{
    long long ans = 0;
    for (long long i = 19; i >= 0; i--)
    {
        long long uu = up[u][i];
        if (!is_upper(uu, v))
        {
            ans = max(ans, lcost[u][i]);
            u = uu;
        }
    }
    for (long long i = 19; i >= 0; i--)
    {
        long long vv = up[v][i];
        if (!is_upper(vv, u))
        {
            ans = max(ans, lcost[v][i]);
            v = vv;
        }
    }
    return ans;
}
long long lca(long long u, long long v)
{
    if (is_upper(v, u))
        return u;
    for (long long i = 19; i >= 0; i--)
    {
        long long uu = up[u][i];
        if (!is_upper(v, uu))
        {
            u = uu;
        }
    }
    return up[u][0];
}
long long find_set(long long v)
{
    if (v == parrent[v])
        return v;
    return parrent[v] = find_set(parrent[v]);
}
void union_set(long long a, long long b)
{
    a = find_set(a);
    b = find_set(b);
    if (runk[a] < runk[b])
        swap(a, b);
    parrent[b] = a;
    runk[a] += b;
}
void make_set(long long v)
{
    parrent[v] = v;
    runk[v] = 1;
}
int main()
{
    long long n, m;
    cin >> n >> m;
    tin.resize(n + 1);
    tout.resize(n + 1);
    parrent.resize(n + 1);
    runk.resize(n + 1);
    for (long long i = 0; i < m; i++)
    {
        long long q, q1, c;
        cin >> q >> q1 >> c;
        G.push_back({c, {q, q1}});
    }
    for (long long i = 1; i <= n; i++)
    {
        make_set(i);
    }
    long long cnt = 0;
    sort(G.begin(), G.end());
    for (long long i = 0; i < m; i++)
    {
        long long a = G[i].second.first, b = G[i].second.second;
        if (find_set(a) != find_set(b))
        {
            union_set(a, b);
            cnt += G[i].first;
            Gr[a].push_back({b, G[i].first});
            Gr[b].push_back({a, G[i].first});
        }
    }
    dfs(1, 1, 0);
    for (long long i = 1; i <= m; i++)
    {
        long long acnt = cnt;
        acnt += G[i].first;
        acnt -= cost_l(G[i].second.first, G[i].second.second);
        cout << acnt << endl;
    }
    return 0;
}