是我比较弱的图论题,比赛的时候没出.
传送门
题意:给定一棵树和三个集合,要求你从每个集合中任选一点,在得到三个点u,v,w后再在树上找到一个点r,使得dis(u,r)+dis(v,r)+dis(w,r)最小.
有一个结论是:这个点r一定在路径uv,vw,uw三个路径的交点上.
首先,可以确定的是,这三条路径一定会有交点,(因为是一棵树,树上的一个点到另一个点只有一条路径),当然这个交点唯一.
那么dis(u,r)+dis(v,r)+dis(w,r)=(dis(u,v)+dis(v,w)+dis(u,w))/2
有了这个结论后题目就变简单了:两个集合内各选一个点,计算出满足条件的任意点对的距离和.
三个集合两两枚举处理即可.
计算的时候有个技巧:考虑每条边对答案的贡献即可,即边的两边的属于集合a的元素和属于集合b的元素的数量统计一下即可进行运算.
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200500
#define ll long long
vector<pair<int,ll>>e[MAXN];
ll cnt[MAXN];
int x[MAXN][3];
ll sz[MAXN][3];
long double ans=0;
void solve(int rt,int pre)
{
for(auto it:e[rt]) {
if (it.first == pre)continue;
int so=it.first;
solve(it.first,rt);
ll now=sz[so][0]*(sz[1]