http://acm.hust.edu.cn/vjudge/contest/view.action?cid=78124#problem/F
//想看题目的@willinglive
先求出给出森林每个点所在树的直径。然后并查集维护
合并的时候ans=max(第一棵树的直径,第二棵树的直径,第一棵树的直径/2+第二棵树的直径/2+1)
然后就解决了
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
struct line
{
int s,t;
int next;
}a[600001];
int head[300001];
int edge;
inline void add(int s,int t)
{
a[edge].next=head[s];
head[s]=edge;
a[edge].s=s;
a[edge].t=t;
}
int fa[300001],fx[300001];
int sx[300001];
inline int find(int x)
{
if(x!=fa[x])
fa[x]=find(fa[x]);
return fa[x];
}
int son1[300001],son2[300001];
int p;
int b[300001];
int dep[300001];
inline void dfs(int d)
{
p++;
b[p]=d;
int i;
for(i=head[d];i!=0;i=a[i].next)
{
int t=a[i].t;
if(dep[t]==-1)
{
fx[t]=d;
dep[t]=dep[d]+1;
dfs(t);
if(son1[t]+1>son1[d])
{
son2[d]=son1[d];
son1[d]=son1[t]+1;
}
else if(son1[t]+1>son2[d])
son2[d]=son1[t]+1;
}
}
}
int main()
{
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
int i,j;
int s,t;
for(i=1;i<=m;i++)
{
scanf("%d%d",&s,&t);
edge++;
add(s,t);
edge++;
add(t,s);
}
for(i=1;i<=n;i++)
fa[i]=i;
memset(dep,-1,sizeof(dep));
for(i=1;i<=n;i++)
{
if(dep[i]==-1)
{
dep[i]=0;
p=0;
dfs(i);
int anx=0;
for(j=1;j<=p;j++)
{
fa[b[j]]=i;
anx=max(anx,son1[b[j]]+son2[b[j]]);
}
sx[i]=max(anx,son1[i]+son2[i]);
}
}
int x;
for(i=1;i<=q;i++)
{
scanf("%d",&x);
if(x==2)
{
scanf("%d%d",&s,&t);
int fx=find(s),fy=find(t);
if(fx!=fy)
{
sx[fx]=max(max(sx[fx],sx[fy]),(sx[fx]+1)/2+(sx[fy]+1)/2+1);
fa[fx]=fy;
sx[fy]=sx[fx];
}
}
else
{
scanf("%d",&s);
int fx=find(s);
printf("%d\n",sx[fx]);
}
}
return 0;
}