CF455C Civilization 树的直径
Posted liubainian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF455C Civilization 树的直径相关的知识,希望对你有一定的参考价值。
问题描述
题解
首先,题目给出了 (m) 条边,对这 (n) 个点, (m) 条边组成的森林,跑出每棵树的直径,同时使用并查集维护树的连通性。
考虑合并两棵树的情况:设这两棵树的代表元为 (u,v) ,这棵树的直径有三种来源:
(u) 这棵树的直径
(v) 这棵树的直径
穿过 (u,v) 合并边的一条路径
(u,v) 两棵树的直径是已知的,所以我们只需要考虑最小化第三种情况。
设树 (u,v) 合并时的点为 (rt_u,rt_v) ,此时第三种情况的值为 (frac{maxdis_{rt_u}}{2}+frac{maxdis_{rt_v}}{2}+1)
显然,为了最小化两个 (maxdis) ,这两个点选取的一定是原来两棵树直径的中点。
(mathrm{Code})
#include<bits/stdc++.h>
using namespace std;
template <typename Tp>
void read(Tp &x){
x=0;char ch=1;int fh;
while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
if(ch=='-') ch=getchar(),fh=-1;
else fh=1;
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
x*=fh;
}
const int maxn=300007;
const int maxm=600007;
int n,m,T;
vector<int> G[maxn];
int fa[maxn];
int bel[maxn],cnt;
void add(int x,int y){
G[x].push_back(y);
}
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
int dep[maxn],ans[maxn];
int pos,lst;
void merge(int x,int y){
if(find(x)!=find(y)) fa[fa[x]]=fa[y];
}
void dfs(int x,int col,int dis){
if(bel[x]==col) return;
if(dis>=lst) lst=dis,pos=x;
bel[x]=col;
for(int i=0;i<G[x].size();i++){
int y=G[x][i];
merge(x,y);
dfs(y,col,dis+1);
}
}
void Getmax(){
int mx=-1;
for(int i=1;i<=n;i++){
if(dep[i]>mx) mx=dep[i],pos=i;
}
}
void cz1(){
int x;read(x);
printf("%d
",ans[find(x)]);
}
void cz2(){
int x,y;read(x);read(y);
int xx=find(x),yy=find(y);
if(xx==yy) return;
fa[xx]=yy;
ans[yy]=max(ans[xx],max(ans[yy],(ans[xx]+1)/2+(ans[yy]+1)/2+1));
}
void preprocess(){
for(int i=1;i<=n;i++) fa[i]=i;
}
int main(){
read(n);read(m);read(T);
preprocess();
for(int i=1,x,y;i<=m;i++){
read(x);read(y);
add(x,y);add(y,x);
}
for(int i=1;i<=n;i++){
if(bel[i]) continue;
lst=0,pos=i;
dfs(i,i,0);
lst=0;
dfs(pos,pos,0);
ans[find(i)]=lst;
}
int op;
while(T--){
read(op);
if(op==1) cz1();
else cz2();
}
return 0;
}
以上是关于CF455C Civilization 树的直径的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 455C Civilization 树的直径+并查集
树的直径| CF#615Div3 F. Three Paths on a Tree