2020 China Collegiate Programming Contest, Weihai Site C. Rencontre(lca+树形dp)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2020 China Collegiate Programming Contest, Weihai Site C. Rencontre(lca+树形dp)相关的知识,希望对你有一定的参考价值。

LINK

题意

给定一颗 n n n个节点的树

给定集合 a , b , c a,b,c a,b,c,从每个集合随机选一个点出来

从树中找一个点 x x x使得三点到 x x x的距离和最小

求这个距离和的期望


本质就是求所有组合的距离和大小

对于给定的三点 x , y , z x,y,z x,y,z,显然这个距离和是

( d i s ( x , y ) + d i s ( y , z ) + d i s ( x , z ) ) 2 \\frac{(dis(x,y)+dis(y,z)+dis(x,z))}{2} 2(dis(x,y)+dis(y,z)+dis(x,z))

又因为 d i s ( x , y ) = d e e p [ x ] + d e e p [ y ] − 2 ∗ d e e p [ l c a ( x , y ) ] dis(x,y)=deep[x]+deep[y]-2*deep[lca(x,y)] dis(x,y)=deep[x]+deep[y]2deep[lca(x,y)]

所以我们可以枚举集合 a , b a,b a,b,集合 a , c a,c a,c,集合 b , c b,c b,c两两计算贡献

比如现在是算 a , b a,b a,b集合点间的贡献,从 a a a中拿出点 x x x,从 b b b中拿出点 y y y

那么 d e e p [ x ] deep[x] deep[x]被计算了 b . s i z e ( ) b.size() b.size()次, d e e p [ y ] deep[y] deep[y]被计算了 a . s i z e ( ) a.size() a.size()

然后我们还要计算每个点被作为 l c a lca lca多少次,设 k k k点作为 l c a lca lca s i z siz siz

那么答案还要减去 2 ∗ d e e p [ k ] ∗ s i z 2*deep[k]*siz 2deep[k]siz

但是注意,现在的答案是 a , b a,b a,b集合间任意两点的距离和

这个距离和还需要对每个 c c c集合的点都会作用一次,所以乘以 c . s i z e ( ) c.size() c.size()

同理对集合 b , c b,c b,c,对集合 a , c a,c a,c也计算一遍

最后算期望,除以总方案数即可

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
vector<int>vec[4];
struct edge{
	int to,nxt,w;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int w)
{
	d[++cnt] = ( edge ){v,head[u],w},head[u] = cnt;
}
int n,deep[maxn],siz[maxn][3];
double sum=0; 
void PRE(int u,int fa)
{
	for(int i=head[u];i;i=d[i].nxt )
	{
		int v =  d[i].to;
		if( v==fa )	continue;
		deep[v] = deep[u]+d[i].w;
		PRE(v,u);
	}
}
void dfs(int u,int fa)
{
	if( siz[u][0] && siz[u][1] )	sum -= 2*deep[u];
	for(int i=head[u];i;i=d[i].nxt )
	{
		int v = d[i].to;
		if( v==fa )	continue;
		dfs(v,u);
		sum -= 1ll*2*siz[u][0]*siz[v][1]*deep[u];
		sum -= 1ll*2*siz[u][1]*siz[v][0]*deep[u];
		siz[u][0] += siz[v][0], siz[u][1] += siz[v][1];
	}
}
double solve( vector<int>a,vector<int>b,vector<int>c)
{
	for(auto v:a )	siz[v][0]++;
	for(auto v:b )	siz[v][1]++;
	sum = 0; dfs(1,1);
	for(auto v:a )	sum += 1ll*deep[v]*b.size();
	for(auto v:b )	sum += 1ll*deep[v]*a.size();
	sum = sum*c.size();
	for(int i=1;i<=n;i++)	siz[i][0] = siz[i][1] = 0;
	return sum;
}
int main()
{
	cin >> n;
	for(int i=1;i<n;i++)
	{
		int l,r,w; scanf("%d%d%d",&l,&r,&w);
		add(l,r,w); add(r,l,w);
	}
	for(int i=1;i<=3;i++)	
	{
		int k; cin >> k;
		for(int j=1;j<=k;j++)
		{
			int x; scanf("%d",&x);
			vec[i].push_back( x );
		}
	}
	PRE(1,1);
	double ans = 0;
	ans += solve( vec[1],vec[2],vec[3] );
	ans += solve( vec[1],vec[3],vec[2] );
	ans += solve( vec[2],vec[3],vec[1] );
	ans /= 2;
	double ANS = 1.0*ans/( 1ll*vec[1].size()*vec[2].size()*vec[3].size() );
	printf("%.19lf",ANS);
}

以上是关于2020 China Collegiate Programming Contest, Weihai Site C. Rencontre(lca+树形dp)的主要内容,如果未能解决你的问题,请参考以下文章

2020 China Collegiate Programming Contest, Weihai Site L. Clock Master(分组背包)

2020 China Collegiate Qinhuangdao Site F. Friendly Group(思维+边双连通)

2020 China Collegiate Programming Contest - Mianyang Site J. Joy of Handcraft(线段树模板)

2020 China Collegiate Programming Contest, Weihai Site C. Rencontre(lca+树形dp)

The 2019 China Collegiate Programming Contest Harbin Site

The 2019 China Collegiate Programming Contest Harbin Site F. Fixing Banners