星球大战

星球大战
有一棵树。每次可以攻击树上的某棵子树,然后这棵子树上的每条边有\(\frac{1}{2}\)的概率消失。定义 若攻击以x为根的子树,深度ht(x)为x子树剩余点(与x连通)的最大深度。共q次操作,两种: 1 x.新建一个节点,其父节点为x。2 x.询问若攻击以x为根的子树,x子树的期望深度。 \(q\leq 5\times10^5\)

设dp[i][j]为以i为根的子树,深度<=j的概率.

\(ans=\sum_{dep=1}^{max_h}dep\times(dp[x][dep]-dp[x][dep-1])\)

转移方程:\(dp[x][dep]=\Pi_{y\in son(x)}(\frac{1}{2}+\frac{1}{2}dp[y][dep-1])\)

其中第一个\(\frac{1}{2}\)是x->y的边断掉的概率

\(\frac{1}{2}dp[y][dep-1]\)是x->y没有断掉的概率乘以y节点深度<=dep-1的概率.

对于每次加点,先除以修改前的\(\frac{1}{2}+\frac{1}{2}dp[y][dep-1]\),再乘以修改后的\(\frac{1}{2}+\frac{1}{2}dp[y][dep-1]\)

for(int dep=0;dep<65;++dep)p[id][dep]=1;
while(q--){
    read(op,x);
    if(op==1){
        fa[++id]=x;
        for(int dep=0;dep<65;++dep)p[id][dep]=1;
        double pre=p[x][0];
        p[x][0]*=0.5;
        double now=p[x][0];
        for(int dep=1;(x=fa[x])>0&&dep<65;++dep){
            double tmp=p[x][dep];
            p[x][dep]/=1+pre;//x子儿子y修改前的值
            p[x][dep]*=1+now;//x子儿子y修改后的值
            pre=tmp,now=p[x][dep];
        }
    }else{
        double ans=0;
        for(int dep=1;dep<65;++dep)
            ans+=(double)dep*(p[x][dep]-p[x][dep-1]);
        printf("%.10f\n",ans);
    }
}
posted @ 2020-12-19 23:04  肆之月  阅读(79)  评论(0编辑  收藏  举报