P2195 HXY造公园
题解
由于树上任意一点 \(c\) 到其他点的最大距离 \(= max(dis(c,a),dis(c,b))\),其中 \(ab\) 为直径,易得直径中点该值最小(其他点都要经过中点)
所以两棵树合并要使直径最短,一定是中点相连,但是因为我们只查询直径,所以不需要真的去找中点在哪,只需要维护每棵树的直径就行,然后合并的时候判断一下
即新树的直径要么是树 \(a\) 的直径,要么是树 \(b\) 的直径,要么是各取一半
注意
合并时对直径的修改和建树时对直径的修改是不一样的!
code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int fa[300005];
int finds(int now){return fa[now]==now?now:fa[now]=finds(fa[now]);}
int diam[300005];
int node;
int maxh=0;
vector<int> G[300005];
void dfs(int now,int fa,int height)
{
if(height>maxh)
{
maxh=height;
node=now;
}
for(auto next:G[now])
{
if(next==fa) continue;
dfs(next,now,height+1);
}
}
void solve()
{
int n,m,q;
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
{
fa[i]=i;
diam[i]=0;
}
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
G[x].push_back(y);
G[y].push_back(x);
int fx=finds(x),fy=finds(y);
if(fx==fy) continue;
fa[fx]=fy;
}
for(int i=1;i<=n;i++)
{
if(fa[i]==i)
{
node=i;
dfs(i,i,0);
dfs(node,node,0);
diam[i]=maxh;
maxh=0;
}
}
while(q--)
{
int op;
cin>>op;
if(op==1)
{
int x;
cin>>x;
cout<<diam[finds(x)]<<'\n';
}
else
{
int x,y;
cin>>x>>y;
int fx=finds(x),fy=finds(y);
if(fx==fy) continue;
fa[fx]=fy;
int rx=diam[fx]-diam[fx]/2,ry=diam[fy]-diam[fy]/2;
diam[fy]=max(max(diam[fy],rx+ry+1),diam[fx]);
//printf("now:%d diam:%d\n",fy,diam[fy]);
}
}
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t=1;
while(t--) solve();
return 0;
}

浙公网安备 33010602011771号