gym102798C Rencontre 2020CCPC威海
https://codeforces.com/gym/102798/problem/C
比賽的時候列舉3個點的中心點然後嗯算方案數,寫了100多行的dfs計數。。。然後wa 3
然而這題只要想到,3個點到中心點的最小距離,要麼一條鏈在中間點上,要麼在3叉路口上,這兩種情況都可以拆成從a-b,b-c,a-c的路徑之和/2
然後這個問題就轉換成了3組獨立問題,每組就是兩個人任選2個點之間的期望距離之和
那麼就直接dfs下去算每條邊的貢獻就行了,每條邊的貢獻就是連線的兩端連通塊中a,b的數量乘起來,a*b,b*a,a*c,c*a,b*c,c*b6種算一算就行了
md回去我要把我的嗯算給調出來
#include<bits/stdc++.h>
using namespace std;
typedef __int128 ll;//__int128!!!
const int maxl=2e5+10;
int n,m[4],tot;
ll sumdis[4][4],num[4][maxl];
struct ed{int v,l;};
vector<ed> e[maxl];
bool in[4][maxl];
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n-1;i++)
{
int u,v,l;
scanf("%d%d%d",&u,&v,&l);
e[u].push_back(ed{v,l});
e[v].push_back(ed{u,l});
}
for(int i=1;i<=3;i++)
{
scanf("%d",&m[i]);
for(int j=1;j<=m[i];j++)
{
int x;scanf("%d",&x);
in[i][x]=true;
}
}
}
inline void predfs(int u,int fa)
{
for(int i=1;i<=3;i++)
if(in[i][u])
num[i][u]=1;
for(ed ee:e[u])
if(ee.v!=fa)
{
int v=ee.v;
predfs(v,u);
for(int i=1;i<=3;i++)
for(int j=i+1;j<=3;j++)
sumdis[i][j]+=((m[i]-num[i][v])*num[j][v]+(m[j]-num[j][v])*num[i][v])*ee.l;
for(int i=1;i<=3;i++)
num[i][u]+=num[i][v];
}
}
inline void mainwork()
{
predfs(1,0);
}
inline void print()
{
double ans=0;
for(int i=1;i<=3;i++)
for(int j=i+1;j<=3;j++)
ans+=1.0*sumdis[i][j]/m[i]/m[j];
ans/=2;
printf("%.10f",ans);
}
int main()
{
prework();
mainwork();
print();
return 0;
}