Codeforces 455C
题目
中文题意http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1427
思路
判断是否在一个区域用并查集就可以实现,求最长路径我用的是两遍dfs,就可以求出,对于合并,去两个区域最长部分的中间点连边,保证最短,貌似dfs很慢,递归的并查集还超了。
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=3*1e5+10;
int n,m,q;
int tot,head[maxn];
int fa[maxn],len[maxn];
int maxx,id;
struct node
{
int next;
int to;
} edge[maxn];
void addedge(int from,int to)
{
edge[tot].to=to;
edge[tot].next=head[from];
head[from]=tot++;
}
int Find(int x)
{
int k, j, r;
r = x;
while(r != fa[r])
r = fa[r];
k = x;
while(k != r)
{
j = fa[k];
fa[k] = r;
k = j;
}
return r;
}
void dfs1(int u,int fa,int dep)
{
if(dep>maxx)
{
maxx=dep;
id=u;
}
for(int i=head[u]; ~i; i=edge[i].next)
{
int v=edge[i].to;
if(v==fa) continue;
dfs1(v,u,dep+1);
}
}
int main()
{
memset(head,-1,sizeof(head));
memset(len,-1,sizeof(len));
tot=0;
scanf("%d %d %d",&n,&m,&q);
for(int i=1; i<=n; i++)
fa[i]=i;
for(int i=0; i<m; i++)
{
int a,b;
scanf("%d %d",&a,&b);
addedge(a,b);
addedge(b,a);
int x=Find(a);
int y=Find(b);
fa[x]=y;
}
for(int i=0; i<q; i++)
{
int op;
int a,b;
scanf("%d",&op);
if(op==1)
{
scanf("%d",&a);
int x=Find(a);
if(len[x]==-1)
{
maxx=0,id=x;
dfs1(x,-1,0);
maxx=0;
dfs1(id,-1,0);
printf("%d\n",len[x]=maxx);
}
else
printf("%d\n",len[x]);
}
else if(op==2)
{
scanf("%d %d",&a,&b);
int x=Find(a);
int y=Find(b);
if(x==y) continue;
if(len[x]==-1)
{
maxx=0,id=x;
dfs1(x,-1,0);
maxx=0;
dfs1(id,-1,0);
len[x]=maxx;
}
if(len[y]==-1)
{
maxx=0,id=y;
dfs1(y,-1,0);
maxx=0;
dfs1(id,-1,0);
len[y]=maxx;
}
fa[x]=y;
int t1=len[x]%2==0?len[x]/2:len[x]/2+1;
int t2=len[y]%2==0?len[y]/2:len[y]/2+1;
len[y]=max(t1+t2+1,max(len[x],len[y]));
}
}
return 0;
}