C - Rencontre Gym - 102798C
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C - Rencontre Gym - 102798C相关的知识,希望对你有一定的参考价值。
C - Rencontre Gym - 102798C
参考题解:
参考一
参考二
题意:
有一棵树,树上的点分为三种,(一个点可以为多种),现在分别在三种点中随机选一点a,b,c,然后找到一个合适的v,使得f=min(dis(a,v)+dis(b,v)+dis(c,v))
求出f的期望
题解:
f = min(dis(a,v)+dis(b,v)+dis(c,v)) = min{1/2( dis(a,b)+ dis(b,c) +dis(a,c) )}
E(f) = 1/2( E(dis(a,b))+E(dis(a,c))+E(dis(b,c)) )
这样a,b,c就是独立的三组,我们要求任意两组内所有点的距离的期望,咋求?
|a|表示集合a内的元素数量
现在问题就是如何快速求任意两点距离和
这个我们可以用换根法来求
对于边(u,v),其对答案的贡献就是siz[v] * (n-siz[v]) * w
siz[v]表示v的子树中节点数量
n-siz[v]表示非v的子树的节点数量
这两部分中点都可以相互连接
代码中siz[v][1]:表示在v的子树中属于块1的点的数量
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
struct Edge {
int v;
ll w;
};
vector<Edge> g[N];
ll cnt[4], siz[N][4];
double ans;
void dfs1(int u, int fa) {
for(auto e : g[u]) {
int v = e.v;
if(v == fa) continue;
dfs1(v, u);
for(int i = 1;i <= 3; i++) {
siz[u][i] += siz[v][i];
}
}
}
void dfs2(int u, int fa) {
for(auto e : g[u]) {
int v = e.v;
if(v == fa) continue;
dfs2(v, u);
for(int i = 1;i <= 3; i++) {
for(int j = 1;j <= 3; j++) {//枚举任意两个块
if(i == j) continue;
ans += 1.0 * ((siz[1][i] - siz[v][i]) * siz[v][j] * 1.0 * e.w / (cnt[i] * cnt[j]) / 2.0);
/*
(siz[1][i] - siz[v][i])表示在子树v之外的属于块i的点的数量
siz[v][j]表示在子树v之内的属于块j的点的数量
*/
}
}
}
}
void solve() {
int n; cin >> n;
for(int i = 1;i < n; i++) {
int u, v; ll w; cin >> u >> v >> w;
g[u].push_back(Edge{v, w});
g[v].push_back(Edge{u, w});
}
for(int i = 1;i <= 3; i++) {
cin >> cnt[i];
for(int j = 1;j <= cnt[i]; j++) {
int x;
cin >> x;
siz[x][i]++;
}
}
dfs1(1, -1);
dfs2(1, -1);
printf("%.12f\\n",ans);
}
int main() {
solve();
return 0;
}
以上是关于C - Rencontre Gym - 102798C的主要内容,如果未能解决你的问题,请参考以下文章
2016 USP-ICMC-Codeforces-Gym101063C-Sleep Buddies Gym101063F-Bandejao Gym101063J-The Keys