Codeforces 455C
题目链接:http://acm.hust.edu.cn/vjudge/problem/52671
题目大意:
给出一个初始森林,支持两种操作:
(1)输出某个点所在树的直径长度
(2)添加一条边合并两棵树,使新的树的直径长度最小
分析:
每棵树用并查集维护,同时维护每棵树直径长度,初始图两遍DFS找出直径,合并两棵树时顺便维护一下直径长度,具体看代码。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define sz(x) (int)(x.size())
using namespace std;
const int maxn=300000+23;
int n,m,q,k,x,y,p,maxd,F[maxn],path[maxn];
bool vis[maxn][3];
vector<int> G[maxn];
int find(int k) {return (F[k]==k)?k:F[k]=find(F[k]);}
void merge(int x,int y)
{
x=find(x),y=find(y);
if (x==y) return;
F[x]=y;
path[y]=max(path[x],max(path[y],(path[x]+1)/2+(path[y]+1)/2+1));
path[x]=0; //拿原来两棵树直径与新树直径比较
}
void DFS(int k,int d,int type)
{
vis[k][type]=1;
if (d>maxd) maxd=d,p=k;
rep(i,0,sz(G[k])-1)
if (!vis[G[k][i]][type]) DFS(G[k][i],d+1,type);
}
void init()
{
memset(vis,0,sizeof(vis));
memset(path,0,sizeof(path));
rep(i,1,n)
if (!vis[i][0])
{
maxd=0,DFS(i,0,0);
maxd=0,DFS(p,0,1);
path[find(i)]=maxd; //DFS找直径
}
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
rep(i,1,n) F[i]=i;
rep(i,1,m)
{
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
merge(x,y);
}
init();
rep(i,1,q)
{
scanf("%d",&k);
if (k==1)
{
scanf("%d",&x);
printf("%d\n",path[find(x)]);
}
else
{
scanf("%d%d",&x,&y);
merge(x,y);
}
}
return 0;
}

浙公网安备 33010602011771号