题目描述
有一个村庄居住着 nn 个村民,有 n-1n−1 条路径使得这 nn 个村民的家联通,每条路径的长度都为 11。现在村长希望在某个村民家中召开一场会议,村长希望所有村民到会议地点的距离之和最小,那么村长应该要把会议地点设置在哪个村民的家中,并且这个距离总和最小是多少?若有多个节点都满足条件,则选择节点编号最小的那个点。
输入格式
第一行,一个数 nn,表示有 nn 个村民。
接下来 n-1n−1 行,每行两个数字 aa 和 bb,表示村民 aa 的家和村民 bb 的家之间存在一条路径。
输出格式
一行输出两个数字 xx 和 yy。
xx 表示村长将会在哪个村民家中举办会议。
yy 表示距离之和的最小值。
输入输出样例
输入 #1复制
4 1 2 2 3 3 4
输出 #1复制
2 4
说明/提示
数据范围
对于 70\%70% 数据 n \le 10^3n≤103。
对于 100\%100% 数据 n \le 5 \times 10^4n≤5×104。
题解:
就是比较明显的求重心吧。第二问就是再跑个dp,总长度为每个结点的长度之和加上节点数-1.
/*keep on going and never give up*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define db(x) cerr<<(#x)<<" "<<(x)<<" "<<endl;
#define endl "\n"
#define fast std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn=2e5+10;
int n,w[maxn],ans=1e14,sum=1e14;
vector<int>e[maxn];
int dfs(int x,int fa){
int k=0,ma=0;
for(auto v:e[x]){
if(v==fa) continue;
int tep=dfs(v,x);
k+=tep;ma=max(ma,tep);
}
ma=max(ma,n-k-1);
if(ma<sum||(ma==sum&&x<ans)) sum=ma,ans=x;
return k+1;
}
int dfs1(int x,int fa,bool s){
int res=0,tep=0;w[x]=1;
for(auto v:e[x]){
if(v==fa) continue;
tep+=dfs1(v,x,0);
w[x]+=w[v];
}
return tep+w[x]-1;
}
signed main(){
fast
cin>>n;
for(int i=1;i<n;i++){
int x,y;cin>>x>>y;
e[x].push_back(y);e[y].push_back(x);
}
int dd=dfs(1,0);cout<<ans<<" ";
cout<<dfs1(ans,ans,1);
}