1. 程式人生 > >[Codeforces643E][DP]Bear and Destroying Subtrees

[Codeforces643E][DP]Bear and Destroying Subtrees

翻譯

給你一棵初始只有根為1的樹 兩種操作 1 x表示加入一個新點以x為父親 2 x表示以x為根的子樹期望最深深度 每條邊都有12\frac{1}{2}的概率斷裂

題解

性質:我們只用考慮40層以內的節點 因為深度過大的的概率太小不予考慮 設f[i][j]f[i][j]表示以i為根的子樹 最深深度不大於j的概率 計算答案可以直接 (f[x][i]f[x][i1])i\sum(f[x][i]-f[x][i-1])*i 考慮一個點加入的影響 首先期望深度為0的話肯定是12\frac{1}{2}的兒子個數次方 一層層往上更新 第一個祖先 只會影響到他的f[x][1] 第二個祖先 只會影響到他的f[x][2],大於2的我們達不到,小於2的斷了我們這條邊還存在影響 … 直接更新即可

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void write(int x) { if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+'0'); } inline void print(int x){write(
x);printf(" ");} double f[510000][45]; int fa[510000],son[510000]; double pow_mod(double a,int b) { double ret=1; while(b) { if(b&1)ret=ret*a; a=a*a;b>>=1; } return ret; } int main() { int o=1; for(int i=0;i<=40;i++)f[1][i]=1; int T=read();while(T--) { int op=read(),x=read(); if(op==1) { o++;fa[o]=x;son[x]++; double lst=f[x][0]; f[x][0]=pow_mod(0.5,son[x]); for(int i=0;i<=40;i++)f[o][i]=1; for(int i=1;i<=40;i++) { int u=fa[x];if(!u)break; double gg=f[u][i]; f[u][i]/=(0.5+0.5*lst); f[u][i]*=(0.5+0.5*f[x][i-1]); lst=gg;x=u; } } else { double ans=0.0; for(int i=1;i<=40;i++)ans+=(f[x][i]-f[x][i-1])*(double)i; printf("%.10lf\n",ans); } } return 0; }