2020ccpc威海 Rencontre
太可惜了,难过
真的难受啊
对于树上三个点a,b,c 汇于一个点的最短路和 ans,有dis(a,b) + dis(b,c) + dis(c,a) = ans * 2
知道这个以后就可以用换根dp解决了,假设dp[x][i]表示所有i颜色的节点到x的距离和
具体可以看代码,
注意答案会爆long long
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 2e5+11;
ll gcd(ll a,ll b){
return b == 0 ? a:gcd(b,a%b);
}
struct Node{
int p;
ll len;
Node(int a,ll ln):p(a),len(ln){}
};
vector<Node>G[maxn];
void add(int x,int y,ll len){
G[x].push_back(Node(y,len));
}
ll dp[maxn][5];//i号点到x 的距离和
ll cnt[maxn][5];
int dfs(int x,int fa){
dp[x][1] = dp[x][2] = dp[x][3] = 0;
int l = G[x].size();
for(int i=0;i<l;i++){
int p = G[x][i].p;
ll len = G[x][i].len;
if(p == fa) continue;
dfs(p,x);
for(int j=1;j<=3;j++){
cnt[x][j] += cnt[p][j];
dp[x][j] += dp[p][j] + len * cnt[p][j];
}
}
return 0;
}
int dfs2(int x,int fa){
int l = G[x].size();
for(int i=0;i<l;i++){
int p = G[x][i].p;
ll len = G[x][i].len;
if(p == fa) continue;
for(int j=1;j<=3;j++){
dp[p][j] += dp[x][j] - dp[p][j] - cnt[p][j]*len + (cnt[x][j] - cnt[p][j])*len;
cnt[p][j] = cnt[x][j];
}
dfs2(p,x);
}
return 0;
}
double a[4];
int list[maxn][5];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y;
ll len;
scanf("%d %d %lld",&x,&y,&len);
add(x,y,len);
add(y,x,len);
}
ll c = 1;
for(int i=1;i<=3;i++){
int k;
scanf("%d",&k);
c *= k;
a[i] = k;
while(k--){
int x;
scanf("%d",&x);
cnt[x][i] = 1;
list[x][i] = 1;
}
}
dfs(1,-1);
dfs2(1,-1);
c *= 2;
double ans = 0;
double aa = 0;
double bb = 0;
double cc = 0;
for(int i=1;i<=n;i++){
if(list[i][1]){
aa += dp[i][2];
}
if(list[i][2]){
bb += dp[i][3];
}
if(list[i][3]){
cc += dp[i][1];
}
}
double cns = aa * a[3] + bb*a[1] + cc * a[2];
printf("%lf\n",cns/c);
return 0;
}
/*
5
1 2 3
1 3 5
2 4 7
2 5 11
2 2 4
2 1 2
2 1 5
*/
寻找真正的热爱

浙公网安备 33010602011771号