CodeForces 1045D Interstellar battle
作者:互联网
题意
给一棵树和每个结点消失的概率 \(p_i\),有 \(q\) 组询问,每组询问要求:
- 将 \(p_u\) 修改为 \(x\)
- 查询森林的期望连通块数量
思路
题中给出的是每个结点消失的概率,那不妨先 \(p_i \gets 1 - p_i\) 将 \(p_i\) 转化为每个结点出现的概率。
众所周知森林连通块数量 = 点数 - 边数,因此期望连通块数量为 \(\sum\limits_{u=1}^n p_u - \sum\limits_{(u,v) \in E} p_up_v\)。考虑维护这个答案。
令 \(1\) 为根,再维护一个 \(sum_u = \sum\limits_{v \in son_u} p_v\),每次修改就减去原来的 \(p_u\) 和 \(p_u \times sum_u\) 的贡献再加上新的 \(p_u\) 和 \(p_u \times sum_u\) 的贡献。对于父结点单独处理。注意还要修改父结点的 \(sum\)。
时间复杂度 \(O(n + q)\)。
代码
code
/*
p_b_p_b txdy
AThousandSuns txdy
Wu_Ren txdy
Appleblue17 txdy
*/
#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 100100;
int n, m, head[maxn], len, fa[maxn];
ldb p[maxn], sum[maxn];
struct edge {
int to, next;
} edges[maxn << 1];
void add_edge(int u, int v) {
edges[++len].to = v;
edges[len].next = head[u];
head[u] = len;
}
void dfs(int u, int f) {
for (int i = head[u]; i; i = edges[i].next) {
int v = edges[i].to;
if (v == f) {
continue;
}
fa[v] = u;
sum[u] += p[v];
dfs(v, u);
}
}
void solve() {
scanf("%d", &n);
ldb ans = 0;
for (int i = 1; i <= n; ++i) {
scanf("%Lf", &p[i]);
p[i] = 1 - p[i];
ans += p[i];
}
for (int i = 1, u, v; i < n; ++i) {
scanf("%d%d", &u, &v);
++u;
++v;
add_edge(u, v);
add_edge(v, u);
ans -= p[u] * p[v];
}
dfs(1, -1);
scanf("%d", &m);
while (m--) {
int u;
ldb x;
scanf("%d%Lf", &u, &x);
++u;
x = 1 - x;
ans -= p[u];
ans += p[u] * sum[u];
if (u != 1) {
ans += p[u] * p[fa[u]];
sum[fa[u]] -= p[u];
}
ans += x;
ans -= x * sum[u];
if (u != 1) {
ans -= x * p[fa[u]];
sum[fa[u]] += x;
}
p[u] = x;
printf("%.6Lf\n", ans);
}
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}
标签:结点,sum,Interstellar,long,CodeForces,typedef,maxn,battle,define 来源: https://www.cnblogs.com/zltzlt-blog/p/16492881.html