【CodeForces - 697D】Puzzles(概率、期望、樹形dp)

Barney lives in country USC (United States of Charzeh). USC has n cities numbered from 1 through n and n - 1 roads between them. Cities and roads of USC form a rooted tree (Barney's not sure why it is rooted). Root of the tree is the city number 1. Thus if one will start his journey from city 1, he can visit any city he wants by following roads.

Some girl has stolen Barney's heart, and Barney wants to find her. He starts looking for in the root of the tree and (since he is Barney Stinson not a random guy), he uses a random DFS to search in the cities. A pseudo code of this algorithm is as follows:

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)

As told before, Barney will start his journey in the root of the tree (equivalent to call dfs(1)).

Now Barney needs to pack a backpack and so he wants to know more about his upcoming journey: for every city i, Barney wants to know the expected value of starting_time[i]. He's a friend of Jon Snow and knows nothing, that's why he asked for your help.

Input

The first line of input contains a single integer n (1 ≤ n ≤ 105) — the number of cities in USC.

The second line contains n - 1 integers p2, p3, ..., pn (1 ≤ pi < i), where pi is the number of the parent city of city number i in the tree, meaning there is a road between cities numbered pi and i in USC.

Output

In the first and only line of output print n numbers, where i-th number is the expected value of starting_time[i].

Your answer for each city will be considered correct if its absolute or relative error does not exceed 10 - 6.

Examples

input

Copy

7
1 2 1 1 4 4

output

Copy

1.0 4.0 5.0 3.5 4.5 5.0 5.0 

input

Copy

12
1 1 2 2 4 4 3 3 1 10 8

output

Copy

1.0 5.0 5.5 6.5 7.5 8.0 8.0 7.0 7.5 6.5 7.5 8.0 

題意:

給一段僞代碼,代表到一個節點時隨機遍歷其孩子結點,問每個結點的遍歷時間的期望。

思路:(參考博客

每個結點的遍歷時間與父節點遍歷時間和父節點的其他子樹有關。假設父節點爲u,其子節點個數爲k。則遍歷方式總共與k!種,考慮其中兩顆子樹v,w。假設要求v的,則這兩個子樹的關係就是w在v前面,和w在v後面。而且這兩種的出現的概率四相同的,並且後者是不會對v的遍歷時間產生影響,因此只考慮前者。設all[w]代表w結點及其子節點的個數,則w這顆子樹對v的貢獻就是(all[w]+0)/2,一半的概率會帶來all[w]的貢獻,另一半無貢獻。因此在求一顆子樹的遍歷時間期望時,就是父節點的遍歷時間的期望加上其他k-1個結點的貢獻再+1。這裏的加1是因爲v結點的遍歷時間是上一個遍歷結點的時間+1。設dp數組爲某個點遍歷時間的期望,son代表某個點的孩子結點的數量。轉移方程爲:dp[v]=dp[u]+(son[u]-son[v]-1)/2+1

對於這種問題,可以簡化考慮,首先是隻考慮兩層之間的關係,其餘的都轉換爲兩層之間關係。然後就是考慮子結點與其他結點的關係時,考慮是不是每一個其他子樹對當前的子樹的影響是一樣的,如果是這樣,那就考慮兩個子樹之間關係的轉移,然後多個子樹求個加和就可以。

ac代碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<vector>
#include<unordered_map>
#define mod (1000000007)
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
struct node{
	int v,nxt;
}side[maxn<<1];
int head[maxn],cnt=0,son[maxn];
double dp[maxn]={0};
void add(int x,int y){
	side[cnt].v=y;
	side[cnt].nxt=head[x];
	head[x]=cnt++;
}
void dfs1(int u,int fa){
	for(int i=head[u];i!=-1;i=side[i].nxt){
		int ty=side[i].v;
		if(ty==fa)continue;
		dfs1(ty,u);
		son[u]+=son[ty]+1;
	}
}
void dfs2(int u,int fa){
	dp[u]=dp[fa]+(son[fa]-son[u]-1)/2.0+1;
	for(int i=head[u];i!=-1;i=side[i].nxt){
		int ty=side[i].v;
		if(ty==fa)continue;
		dfs2(ty,u);
	}
}
int main(){
	int n,fa;
	scanf("%d",&n);
	for(int i=0;i<=n;i++) head[i]=-1;
	for(int i=2;i<=n;i++){
		scanf("%d",&fa);
		add(fa,i);
		add(i,fa);
	}
	dfs1(1,0); 
	dp[1]=1;son[0]=son[1]+1,dp[0]=0;
	dfs2(1,0);
	for(int i=1;i<=n;i++) printf("%.6f%c",dp[i],i==n?'\n':' ');
	return 0;
} 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章