[Codeforces643E][DP]Bear and Destroying Subtrees
阿新 • • 發佈:2018-12-13
翻譯
給你一棵初始只有根為1的樹 兩種操作 1 x表示加入一個新點以x為父親 2 x表示以x為根的子樹期望最深深度 每條邊都有的概率斷裂
題解
性質:我們只用考慮40層以內的節點 因為深度過大的的概率太小不予考慮 設表示以i為根的子樹 最深深度不大於j的概率 計算答案可以直接 考慮一個點加入的影響 首先期望深度為0的話肯定是的兒子個數次方 一層層往上更新 第一個祖先 只會影響到他的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;
}