JZOJ 4647 寻找 【NOIP2016提高A组模拟7.17】

寻找

题目大意

给出你一棵根节点为1的,共有n个点的树,现在给出除了1以外其他n-1节点的父亲。
现在给出你一个程序

starting_time是一个容量为n的数组
current_time = 0
dfs(v):        
       current_time = current_time + 1        
       starting_time[v] = current_time        
       将children[v]的顺序随机排列 (每个排列的概率相同)        
       // children[v]v的直接儿子组成的数组        
       for u in children[v]:               
               dfs(u)

求每一个点starting_time的期望值。

输入格式

第一行一个数N,表示节点数
第二行N-1个数,第i个数表示节点i+1的父节点。

输出格式

一行N个小数,第i个数表示starting_time[i]的期望值。

样例输入

7
1 2 1 1 4 4

样例输出

1.0 4.0 5.0 3.5 4.5 5.0 5.0

数据范围

对于30%的数据,N<=1000
对于100%的数据,N<=100000

题解

假设我们已经知道了starting_time[u],我们简写成Su
设点u的一个儿子为v
如果我们想要知道Sv,那我们就需要知道在遍历到点v之前,u的哪些其他子树已经被遍历过了。

我们设第i种选择子树(是否遍历)方案的期望值为Ki,则假设当前选到第j棵子树,1~~j-1的子树已经选完,有m种选择方案,则当前的点v的期望值FSu+1+{{\sum_{i=1}^{m}K_i}\over m}$。

现在我们对第j棵子树进行分类讨论。
如果不选第j棵子树,则有m种方案,期望和为mi=1Ki
如果选择第j棵子树,则也有m种方案,期望和为mi=1(Ki+Sizej)
其中Sizej表示以j为根节点的子树的大小(有多少个节点)。

所以由选完1~~j-1的子树到选完1~~j的子树的过程中,新的F=Su+1+mi=1Ki+mi=1(Ki+Sizej)m+m
化简得
F=F+Sizej2
所以最后

Sv=Su+1+k1i=1Sizei2(假设点uk个儿子)

Sv=Su+1+SizeuSizev12

做一次递归并求期望值即可,一开始要预处理Size数组。

Code(Pascal)

var
    qw:array[0..100100] of extended;
    bj:array[0..100100,1..2] of longint;
    fa,en,size:array[0..101000] of longint;
    n,m,j,k,l,i,o,p:longint;
procedure qsort(l,r:longint);
    var
        i,j,m:longint;
    begin
        i:=l;
        j:=r;
        m:=bj[(l+r) div 2,1];
        repeat
            while bj[i,1]<m do inc(i);
            while bj[j,1]>m do dec(j);
            if i<=j then
            begin
                bj[0]:=bj[i];
                bj[i]:=bj[j];
                bj[j]:=bj[0];
                inc(i);
                dec(j);
            end;
        until i>j;
        if l<j then qsort(l,j);
        if i<r then qsort(i,r);
    end;
procedure dg(o:longint);
    var
        xcqw:extended;
        i:longint;
    begin
        for i:=en[o-1]+1 to en[o] do
        begin
            dg(bj[i,2]);
            size[o]:=size[o]+size[bj[i,2]];
        end;
        inc(size[o]);
    end;
procedure bl(o:longint);
    var
        i:longint;
    begin
        for i:=en[o-1]+1 to en[o] do
        qw[bj[i,2]]:=qw[o]+(size[o]-size[bj[i,2]]-1)/2+1;
        for i:=en[o-1]+1 to en[o] do
        bl(bj[i,2]);
    end;
begin
    readln(n);
    for i:=2 to n do
    begin
        read(fa[i]);
        bj[i-1,1]:=fa[i];
        bj[i-1,2]:=i;
        inc(en[fa[i]]);
    end;
    qsort(1,n-1);
    qw[1]:=1;
    for i:=2 to n do
    en[i]:=en[i-1]+en[i];
    dg(1);
    bl(1);
    for i:=1 to n do
    write(qw[i]:0:1,' ');
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值