gym102798C Rencontre 2020CCPC威海

二分抄程式碼發表於2020-11-13

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;
}