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)相关的知识,希望对你有一定的参考价值。
题意
给定一颗 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]−2∗deep[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 2∗deep[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