CF643E Bear and Destroying Subtrees

一、题目

点此看题

二、解法

首先考虑一个朴素 d p dp dp,设 d p [ i ] [ j ] dp[i][j] dp[i][j]为第 i i i个点的树深度不大于 j j j的概率(方便转移,用的时候减一下就行了),转移就考虑当前这条边断不断裂,转移方程如下:
d p [ u ] [ i ] = ∏ d p [ v ] [ i − 1 ] + 1 2 dp[u][i]=\prod\frac{dp[v][i-1]+1}{2} dp[u][i]=2dp[v][i1]+1这样做的话时间复杂度 O ( q 3 ) O(q^3) O(q3),观察到本题不需要取模,且允许精度误差,而且一个点对它祖先的影响是指数级下降的,所以我们定一个值 x x x,表示树高超过 x x x我们就不再考虑它的影响,这样 d p dp dp树组和转移的复杂度就会大大降低,时间复杂度 O ( q x 2 ) O(qx^2) O(qx2),对于此题我们把 x x x定为 50 50 50足矣,贴个代码。

#include <cstdio>
#define db double
const int N = 50;
const int M = 500005;
int read()
{
    int x=0,flag=1;
    char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,m,k,t,fa[M],q[M];db dp[M][N];
void add(int x,int y)
{
    t=0;
    for(int i=0;i<N;i++)
        dp[x][i]=1;
    for(int i=1,k=y;i<N && k;i++,k=fa[k])
        q[++t]=k;
    for(int i=t;i>1;i--)
    {
        int u=q[i],v=q[i-1];
        for(int j=1;j<N;j++)
            dp[u][j]/=0.5*(dp[v][j-1]+1);
    }
    dp[y][0]*=0.5;
    for(int i=1;i<t;i++)
    {
        int u=q[i+1],v=q[i];
        for(int j=1;j<N;j++)
            dp[u][j]*=0.5*(dp[v][j-1]+1);
    }
}
db ask(int x)
{
    db r=0;
    for(int i=1;i<N;i++)
        r+=(dp[x][i]-dp[x][i-1])*i;
    return r;
}
signed main()
{
    n=read();
    m++;
    for(int i=0;i<N;i++)
        dp[m][i]=1;
    while(n--)
    {
        int op=read(),x=read();
        if(op==1)
        {
            m++;
            add(m,fa[m]=x);
        }
        if(op==2)
            printf("%.10lf\n",ask(x));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值