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 ∑i=1n∑j=i+1ndis(i,j)∑^n_{i=1}∑^n_{j=i+1}dis(i,j)∑i=1n∑j=i+1ndis(i,j), where dis(i,j)dis(i,j)dis(i,j) represents the number of edges of the path from iii to jjj. He is happy with only the function value.
Input
The first line contains a number n(2<=n<=100000)n(2<=n<=100000)n(2<=n<=100000). In each of the following n−2n−2n−2 lines, there are two numbers uuu and vvv, meaning that there is an edge between uuu and vvv. The input is guaranteed to contain exactly two trees.
Output
Just print the minimum function value.
Sample Input
3
1 2
Sample Output
4
题意:
给定一棵树的n−2n-2n−2条边,让你加上一条边,让他变为一棵树,并且满足∑i=1n∑j=i+1ndis(i,j)∑^n_{i=1}∑^n_{j=i+1}dis(i,j)∑i=1n∑j=i+1ndis(i,j)最小,dis(i,j)dis(i,j)dis(i,j)是iii到jjj的距离。
题解:
首先我们对两个树进行dp,对每个节点计算g[x]g[x]g[x],表示为以xxx为根节点
的子树中所有节点到根节点的距离之和。
然后我们再dfs一次计算对于一个节点来说,同一个树的其他所有点到这个点的距离之和p[i]p[i]p[i]
那么(∑p[i])/2(\sum p[i])/2(∑p[i])/2是不加边之前的答案。那么加边之后的答案,只需要找到两个数各自最小的两个p[i]p[i]p[i],设为a1a1a1,a2a2a2,答案就是(a1+c1)∗c2+a2∗c1(a1+c1)*c2+a2*c1(a1+c1)∗c2+a2∗c1
#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;
}