bzoj 4726 [POI2017]Sabota? 树形dp

 [POI2017]Sabota?

Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special Judge
Submit: 741  Solved: 314
[Submit][Status][Discuss]

Description

某个公司有n个人, 上下级关系构成了一个有根树。其中有个人是叛徒(这个人不知道是谁)。对于一个人, 如果他
下属(直接或者间接, 不包括他自己)中叛徒占的比例超过x,那么这个人也会变成叛徒,并且他的所有下属都会变
成叛徒。你要求出一个最小的x,使得最坏情况下,叛徒的个数不会超过k。
 

 

Input

第一行包含两个正整数n,k(1<=k<=n<=500000)。
接下来n-1行,第i行包含一个正整数p[i+1],表示i+1的父亲是p[i+1](1<=p[i+1]<=i)。
 

 

Output

输出一行一个实数x,误差在10^-6以内都被认为是正确的。
 

 

Sample Input

9 3
1
1
2
2
2
3
7
3

Sample Output

0.6666666667

HINT

 

答案中的x实际上是一个无限趋近于2/3但是小于2/3的数

因为当x取2/3时,最坏情况下3,7,8,9都是叛徒,超过了k=3。

 

并且带头叛变的人一定是从某个叶子往上走一条链

 

因为如果i没有带头叛变,那么i的父亲也一定不会带头叛变,证明显然

 

f[i]表示i不带头叛变的话最小的x

 

那么我们对所有子树大小>k的f值取max即是答案

 

f[i]=max j为i的儿子 (min(f[j],siz[j]/(siz[i]-1))

 

因为对于i的一个儿子j,假如i因为j的子树里的叛徒比例大于x而带头叛变,那么既要满足x<=(j的子树大小占i的子树大小的比例),还要满足j带头叛变即x<=f[j],所以对两个量取min

 

那么如果i不叛变,那么就不能满足任意一个条件,所以对所有的取max

 

对于叶子,f[i]=1,因为不管怎样叶子本身就是叛徒,可以视为不需要条件就可以带头叛变,即只有当x>1时才不会叛变

 

 1 #include<cstring>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<cmath>
 6 #include<map>
 7 
 8 #define N 500007
 9 #define ll long long
10 using namespace std;
11 inline ll read()
12 {
13     ll x=0,f=1;char ch=getchar();
14     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
15     while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
16     return x*f;
17 }
18 
19 int n,k;
20 int cnt,hed[N],rea[N<<1],nxt[N<<1];
21 int siz[N];
22 double f[N],ans;
23 
24 void add(int u,int v)
25 {
26     nxt[++cnt]=hed[u];
27     hed[u]=cnt;
28     rea[cnt]=v;
29 }
30 void dfs(int u)
31 {
32     siz[u]=1;
33     for (int i=hed[u];i!=-1;i=nxt[i])
34     {
35         int v=rea[i];
36         dfs(v);
37         siz[u]+=siz[v];
38     }
39     if (hed[u]==-1) f[u]=1;
40     else
41     {
42         for (int i=hed[u];i!=-1;i=nxt[i])
43         {
44             int v=rea[i];
45             f[u]=max(f[u],min(1.0*siz[v]/(siz[u]-1),f[v]));
46         }
47     }
48     if (siz[u]>k) ans=max(ans,f[u]);
49 }
50 int main()
51 {
52     memset(hed,-1,sizeof(hed));
53     n=read(),k=read();
54     for (int i=2;i<=n;i++)
55         add(read(),i);
56     dfs(1);
57     printf("%.8lf\n",ans);
58 }

 

 
posted @ 2018-04-09 14:32  Kaiser-  阅读(126)  评论(0编辑  收藏  举报