New Year Santa Network
分类:树形dp、思维、数学
1.题意概述
- 给你由n个节点构成的树,有(n-1)条边,随机选取其中三个节点a、b、c,定义dist=dis(a,b)+dis(b,c)+dis(c,a),现在有q次操作,每次选取某条边,使得它的边权由原先的wi变成li,问你每次操作以后的期望E(dist)是多少?
2.解题思路
- 根据期望性质E[dis(a,b)+dis(b,c)+dis(c,a)]=E[dis(a,b)]+E[dis(b,c)]+E[dis(c,a)]
- 方法一:按边考虑,n个点中任意取3个点的取法是C3n种,我们考虑每条边出现的概率。如果我们选定边ab,那么第三个点c就在剩下的
(n−2) 个点中取,也就是边ab会出现(n−2)次,假设这条边下面的儿子个数为son[x],而经过这条边的种类数son[x]⋅(n−son[x]),所以最终概率为pab=son[x](n−son[x])(n−2)C3n,而总的期望就是E(dist)=∑E[dis(i,j)]=pij⋅wij!而统计儿子个数我们可以通过树形dp跑一遍dfs就可以求得,而每条边的权值的变动,只会影响wij,根据期望性质,我们可以先求得边尚未改变的期望,然后减去(lij−wij)⋅pij就是结果! - 方法二:按点考虑,画图容易发现,树中任意选三点构成合法路线,某条边一定会经过两次,那么我们对于这条边两侧的点考虑,假设左侧有a个点,右侧有
b 个点,那么这三个点的选法有C2a⋅C1b+C1a⋅C2b种,结果就是2(C2a⋅C1b+C1a⋅C2b)C3n,下面做法和方法一类似。
- 方法一:按边考虑,n个点中任意取3个点的取法是C3n种,我们考虑每条边出现的概率。如果我们选定边ab,那么第三个点c就在剩下的
3.AC代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define maxn 100010
#define lson root << 1
#define rson root << 1 | 1
#define lent (t[root].r - t[root].l + 1)
#define lenl (t[lson].r - t[lson].l + 1)
#define lenr (t[rson].r - t[rson].l + 1)
#define N 1111
#define eps 1e-6
#define pi acos(-1.0)
#define e exp(1.0)
#define Close() ios::sync_with_stdio(0),cin.tie(0)
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
struct node
{
int to, id;
node(int a, int b) { to = a; id = b; }
};
vector<node> g[maxn];
double p[maxn];
int son[maxn], w[maxn];
void dfs(int u, int fa, int pid, const int &n)
{
son[u] = 1;
int sz = g[u].size();
for (int i = 0; i < sz; i++)
{
int v = g[u][i].to;
int id = g[u][i].id;
if (v != fa)
{
dfs(v, u, id, n);
son[u] += son[v];
}
}
p[pid] = 6.0 * son[u] * (n - son[u]) / n / (n - 1);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
long _begin_time = clock();
#endif
int n, m;
scanf("%d", &n);
for (int i = 1; i < n; i++)
{
int a, b;
scanf("%d%d%d", &a, &b, &w[i]);
g[a].push_back(node(b, i));
g[b].push_back(node(a, i));
}
dfs(1, -1, 0, n);
double ans = 0;
for (int i = 1; i < n; i++)
ans += w[i] * p[i];
scanf("%d", &m);
while (m--)
{
int a, b;
scanf("%d%d", &a, &b);
int delta = w[a] - b;
ans -= delta * p[a];
printf("%.12f\n", ans);
w[a] -= delta;
}
#ifndef ONLINE_JUDGE
long _end_time = clock();
printf("time = %ld ms.", _end_time - _begin_time);
#endif
return 0;
}版权声明:本文为dragon60066原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。