题目链接:点这里!!!
题意:
给你一颗n(n<=10^5)个节点树根为1的树,然后进行dfs,求每个点,在dfs中被访问时间的期望。
let starting_time be an array of length n current_time = 0 dfs(v): current_time = current_time + 1 starting_time[v] = current_time shuffle children[v] randomly (each permutation with equal possibility) // children[v] is vector of children cities of city v for u in children[v]: dfs(u)我们求的就是starting_time[v]的期望pv。
题解:
我们来求一下节点2的期望。
1、我们知道我们要先通过2节点的父亲1才能到2。但2节点什么时候访问是不固定的。
我们假设ri代表i为根的子树,我们能得到下列六种访问次序:
r2 r4 r5
r2 r5 r4
r4 r2 r5
r5 r2 r4
r4 r5 r2
r5 r4 r2
对应的2节点的starting_time[v]分别为2,2,5,3,6,6.我们能得到2节点的期望为p[2]=(2+2+5+3+6+6)/6=4.0
2、但是我们不能这样算,其实我们可以来算r4和r5给2节点的贡献:p[2]=p[1]+1+(3*size(r4)+3*size(r5))/6。
我们发现r4和r5各有一半的情况是出现在2节点的前面的。我们就得出了递推公式:
p[i]=p[fa[i]]+1+(size(fa[i])-size(i)-1)/2 从根节点dfs下来就可以了。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<vector>
#include<bitset>
#include<set>
#include<queue>
#include<stack>
#include<map>
#include<cstdlib>
#include<cmath>
#define LL long long
#define pb push_back
#define pa pair<int,int>
#define clr(a,b) memset(a,b,sizeof(a))
#define lson lr<<1,l,mid
#define rson lr<<1|1,mid+1,r
#define bug(x) printf("%d++++++++++++++++++++%d\n",x,x)
#define key_value ch[ch[root][1]][0]
#pragma comment(linker, "/STACK:102400000000,102400000000")
const LL MOD = 1000000007;
const int N = 100000+15;
const int maxn = 1e5+15;
const int letter = 130;
const LL INF = 1e7;
const double pi=acos(-1.0);
const double eps=1e-10;
using namespace std;
inline int read()
{
int x=0,f=1;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;
}
int n,tot,head[N],dis[N],father[N];
double ans[N];
struct edges{
int to,next;
}e[N<<1];
void addedges(int u,int v){
e[tot].to=v,e[tot].next=head[u],head[u]=tot++;
}
void dfs(int x,int fa){
dis[x]=1;
for(int i=head[x];i!=-1;i=e[i].next){
if(e[i].to==fa) continue;
father[e[i].to]=x;
dfs(e[i].to,x);
dis[x]+=dis[e[i].to];
}
}
void ps(int x,int fa){
if(x!=0)ans[x]=(ans[father[x]]+1.0)+1.0*(dis[father[x]]-dis[x]-1)/2.0;
for(int i=head[x];i!=-1;i=e[i].next){
if(e[i].to==fa) continue;
ps(e[i].to,x);
}
}
int main(){
tot=0,clr(head,-1);
scanf("%d",&n);
int x;
for(int i=2;i<=n;i++){
scanf("%d",&x);
addedges(x,i);
addedges(i,x);
}
addedges(0,1);
ans[0]=0;
dfs(0,-1);
ps(0,-1);
for(int i=1;i<=n;i++) printf("%f ",ans[i]);
puts("");
return 0;
}