CF 643 E. Bear and Destroying Subtrees

Posted mjtcn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF 643 E. Bear and Destroying Subtrees相关的知识,希望对你有一定的参考价值。

E. Bear and Destroying Subtrees

http://codeforces.com/problemset/problem/643/E

题意:

  Q个操作。

  1. 加点,在原来的树上加一个点,之后还是一棵树,初始时一个点。
  2. 让一棵子树内每条边有1/2的概率消失,然后的深度为:剩余的与子树的根联通的点中深度最大的。询问假如攻击这个点,期望深度。

分析:

  可以枚举一个深度,计算概率。

  f[x][i]表示以x为根的子树中,深度为<=x的概率。那么答案就是$sum_{h=1}^{MAX\_H}h imes(f[x][h]-f[x][h-1])$。

  考虑如何求出f数组:直接将所有子树小于等于h的概率相乘,$f[x][h]=prod_{v=son_x}(frac{1}{2}+frac{1}{2}f[v][h-1])$

  考虑如何维护f数组,如果加入一个点,那么只会影响到父节点到根的路径,而且每个点只会影响一个,即距离它为k的点(设为y),只有f[y][k-1]受到影响。因为增加一个点后,它的父节点的0会受到影响(乘1/2),那么父节点的父节点的1就受到影响,以此类推。还可以理解为:因为增加了一个点,y的最长路径不是y-1了, 那么概率也不是1了,因为如果长度为k的概率要求新增的这个点的边断开才行。y的其他的值不受影响吗?f[y][k-2]要求距离它k-1的点必须断开,距离大于k-1的剩下的随便了。 那么,直接暴力修改这条路径即可。每个点除以原来的f[v][h-1],乘以新的f[v][h-1]。

  由于路径长度是很长的(可以5e5),直接暴力修改会T。

  发现如果路径很长之后,它的概率就会非常小,$frac{1}{2^h}$,所以只需确定一个更新的深度,这个深度不会影响精度,然后每次修改这些个点即可。

  具体题解里说明 http://codeforces.com/blog/entry/44754

记录一下当时的想法:f[x][i]为x子树内深度为i的概率。发现转移起来真是麻烦。

首先可以然后它的一个子节点为i,然后其他的节点为0~i,然后,相乘,再除以2。(或者每个点只乘以左边的,那么就不需要除以2了)。然后就需要在记录前缀和,就成了和上面差不多了。

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<cctype>
 7 #include<set>
 8 #include<vector>
 9 #include<queue>
10 #include<map>
11 #define fi(s) freopen(s,"r",stdin);
12 #define fo(s) freopen(s,"w",stdout);
13 using namespace std;
14 typedef long long LL;
15 
16 inline int read() {
17     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch==-)f=-1;
18     for(;isdigit(ch);ch=getchar())x=x*10+ch-0;return x*f;
19 }
20 
21 const int N = 500005;
22 const int H = 60;
23 
24 double f[N][H+2];
25 int fa[N], n = 1;
26 
27 void add(int x) {
28     fa[++n] = x;
29     for (int i=0; i<=H; ++i) f[n][i] = 1;
30     double t1 = f[x][0], t2;
31     f[x][0] *= 0.5;    
32     for (int i=1; i<=H; ++i, x=fa[x]) {        
33         int p = fa[x]; if (!p) break;
34         t2 = f[p][i];
35         f[p][i] = f[p][i] / (0.5 + 0.5 * t1);
36         f[p][i] = f[p][i] * (0.5 + 0.5 * f[x][i - 1]);
37         t1 = t2;
38     }
39 }
40 void query(int x) {
41     double ans = 0;
42     for (int i=1; i<=H; ++i) 
43         ans += i * (f[x][i] - f[x][i - 1]);
44     printf("%.10lf
",ans);
45 }
46 int main() {
47     int Q = read();
48     for (int i=0; i<=H; ++i) f[1][i] = 1;
49     while (Q --) {
50         int opt = read(), a = read();
51         if (opt == 1) add(a);
52         else query(a);
53     }
54     return 0;
55 }

 

以上是关于CF 643 E. Bear and Destroying Subtrees的主要内容,如果未能解决你的问题,请参考以下文章

cf643E. Bear and Destroying Subtrees(期望dp)

CF639F Bear and Chemistry

cf B. Bear and Compressing

CF771C Bear and Tree Jumps 题解

CF573E Bear and Bowling

CF679C(Bear and Square Grid) 经典好题