当前位置: 代码迷 >> 综合 >> [Codeforces643E][DP]Bear and Destroying Subtrees
  详细解决方案

[Codeforces643E][DP]Bear and Destroying Subtrees

热度:63   发布时间:2023-12-19 05:00:11.0

翻译

给你一棵初始只有根为1的树
两种操作
1 x表示加入一个新点以x为父亲
2 x表示以x为根的子树期望最深深度
每条边都有 1 2 \frac{1}{2} 21?的概率断裂

题解

性质:我们只用考虑40层以内的节点 因为深度过大的的概率太小不予考虑
f [ i ] [ j ] f[i][j] f[i][j]表示以i为根的子树 最深深度不大于j的概率
计算答案可以直接
∑ ( f [ x ] [ i ] ? f [ x ] [ i ? 1 ] ) ? i \sum(f[x][i]-f[x][i-1])*i (f[x][i]?f[x][i?1])?i
考虑一个点加入的影响
首先期望深度为0的话肯定是 1 2 \frac{1}{2} 21?的儿子个数次方
一层层往上更新
第一个祖先 只会影响到他的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; }