题意:给出n个城镇,k对学校,k对学校分布在不同的城镇,然后给出2*k个学校所在城镇的编号,然后再给出n-1条边连接的两个城镇,保证每一个城镇都能到达任何一个其他城镇,2*k个学校可以任意配对,要求每一队配对的学校的距离总和最大,每一条边的距离是1
思路:如果对于一个点而言,如果这些学校分布在这个点的左子树和右子树,那么我们可以求出这些学校到这个点的距离然后加起来就是结果,但是题目并不保证这个条件,这时我们可以算每一条边对答案的贡献,对一条边而言,左边如果有a个学校,右边肯定是2*k-a个学校,那么肯定少的那一边要连到多的那一边去,那么答案就是min(a, 2*k-a),这个就直接在树上求结果就行了, 这题答案要用long long 来存,
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stdio.h>
using namespace std;
typedef long long ll;
const int qq = 200000+10;
vector<int>v[qq];
ll dp[qq]={0};
int vis[qq]={0};
ll ans = 0;
ll n,k;
void dfs(int rt, int fa){
if(vis[rt]) dp[rt] = 1;
for(int i=0; i<v[rt].size(); ++i){
int to = v[rt][i];
if(to==fa) continue;
dfs(to, rt);
dp[rt]+=dp[to];
ans+=min(dp[to], 2*k-dp[to]);
}
}
int main(){
scanf("%lld%lld",&n, &k);
int x;
for(int i=1; i<=2*k; ++i){
scanf("%d",&x);
vis[x]++;
}
for(int i=1; i<n; ++i){
int a,b;
scanf("%d%d",&a, &b);
v[a].push_back(b);
v[b].push_back(a);
}
dfs(1, -1);
printf("%lld\n", ans);
return 0;
}