Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 262144/262144 K (Java/Others)
分数:2500
Problem Description
Avin has two trees which are not connected. He asks you to add an edge between them to make them connected while minimizing the function
, where
represents the number of edges of the path from
to
. He is happy with only the function value.
Input
The first line contains a number
. In each of the following
lines, there are two numbers
and
, meaning that there is an edge between
and
. The input is guaranteed to contain exactly two trees.
Output
Just print the minimum function value.
Sample Input
3
1 2
Sample Output
4
题意:
给定一棵树的
条边,让你加上一条边,让他变为一棵树,并且满足
最小,
是
到
的距离。
题解:
首先我们对两个树进行dp,对每个节点计算
,表示为以
为根节点
的子树中所有节点到根节点的距离之和。
然后我们再dfs一次计算对于一个节点来说,同一个树的其他所有点到这个点的距离之和
那么
是不加边之前的答案。那么加边之后的答案,只需要找到两个数各自最小的两个
,设为
,
,答案就是
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n;
vector<int>G[200004];
int bl[200004],sz[200004];
ll g[200004],ans[4],res;
int c[4],rt[4];
void dfs(int x,int bt){
bl[x]=bt;
++c[bt];
sz[x]=1;g[x]=0;
for(int i=0;i<G[x].size();i++){
int to=G[x][i];
if(bl[to])continue;
dfs(to,bt);
sz[x]+=sz[to];
g[x]+=sz[to];
g[x]+=g[to];
}
}
void dfs2(int x,int fa,ll val){
res+=val+g[x];
//cout<<x<<" "<<val+g[x]<<" "<<bl[x]<<" || "<<endl;
if(ans[bl[x]]==-1||(ans[bl[x]]!=-1&&ans[bl[x]]>val+g[x])){
ans[bl[x]]=val+g[x];
}
for(int i=0;i<G[x].size();i++){
int to=G[x][i];
if(to==fa)continue;
dfs2(to,x,val+c[bl[x]]-2*sz[to]+g[x]-g[to]);
}
}
int w33ha(){
res=0;
for(int i=1;i<=n;i++){
G[i].clear();
g[i]=0;
ans[i]=0;
bl[i]=0;
}
c[1]=0;c[2]=0;
rt[1]=0;rt[2]=0;
ans[1]=-1;ans[2]=-1;
for(int i=1;i<=n-2;i++){
int u,v;scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
int blo=0;
for(int i=1;i<=n;i++){
if(!bl[i]){
dfs(i,++blo);
rt[blo]=i;
}
}
//for(int i=1;i<=n;i++)cout<<g[i]<<" ";cout<<endl;
for(int i=1;i<=blo;i++){
dfs2(rt[i],0,0);
}
//for(int i=1;i<=n;i++)cout<<bl[i]<<" ";cout<<endl;
res>>=1;
//cout<<res<<endl;
//cout<<" "<<ans[1]<<" "<<ans[2]<<endl;
printf("%lld\n",res+(ans[1]+c[1])*(c[2])+(ans[2]*c[1]));
return 0;
}
int main(){
while(scanf("%d",&n)!=EOF)w33ha();
return 0;
}