BZOJ 4726: [POI2017]Sabota?

4726: [POI2017]Sabota?

Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special Judge
Submit: 301  Solved: 127
[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。

Source

[Submit][Status][Discuss]

树形DP。

f[i]表示i节点不叛变,最大的x值。

f[u] = max { min(f[v], p[v]) | v是u的儿子 }

其中p[i]是i节点子树大小占父节点所有儿子子树大小的比例。

  1 #include <bits/stdc++.h>
  2 
  3 inline int get_c(void)
  4 {
  5     static const int siz = 1024;
  6 
  7     static char buf[siz];
  8     static char *head = buf + siz;
  9     static char *tail = buf + siz;
 10 
 11     if (head == tail)
 12         fread(head = buf, 1, siz, stdin);
 13 
 14     return *head++;
 15 }
 16 
 17 inline int get_i(void)
 18 {
 19     register int ret = 0;
 20     register int neg = false;
 21     register int bit = get_c();
 22 
 23     for (; bit < 48; bit = get_c())
 24         if (bit == '-')neg ^= true;
 25 
 26     for (; bit > 47; bit = get_c())
 27         ret = ret * 10 + bit - 48;
 28 
 29     return neg ? -ret : ret;
 30 }
 31 
 32 const int maxn = 500005;
 33 const double inf = 2e18;
 34 
 35 int n;
 36 int m;
 37 int edges;
 38 int fa[maxn];
 39 int hd[maxn];
 40 int to[maxn];
 41 int nt[maxn];
 42 
 43 inline void add(int u, int v)
 44 {
 45     nt[edges] = hd[u]; to[edges] = v; hd[u] = edges++;
 46 }
 47 
 48 int size[maxn];
 49 
 50 void dfs1(int u)
 51 {
 52     size[u] = 1;
 53     
 54     for (int i = hd[u]; ~i; i = nt[i])
 55         dfs1(to[i]), size[u] += size[to[i]];
 56 }
 57 
 58 double p[maxn];
 59 
 60 void dfs2(int u)
 61 {
 62     for (int i = hd[u]; ~i; i = nt[i])
 63         dfs2(to[i]);
 64         
 65     if (u != 1)
 66         p[u] = (double)size[u] / (size[fa[u]] - 1);
 67 }
 68 
 69 double f[maxn];
 70 
 71 void dfs3(int u)
 72 {
 73     for (int i = hd[u]; ~i; i = nt[i])
 74         dfs3(to[i]);
 75     
 76     using namespace std;
 77     
 78     for (int i = hd[u]; ~i; i = nt[i])
 79         f[u] = max(f[u], min(p[to[i]], f[to[i]]));
 80         
 81     if (size[u] == 1)
 82         f[u] = 1.0;
 83 }
 84 
 85 signed main(void)
 86 {
 87     n = get_i();
 88     m = get_i();
 89     
 90     memset(hd, -1, sizeof(hd));
 91     
 92     for (int i = 2; i <= n; ++i)
 93         fa[i] = get_i(), add(fa[i], i);
 94         
 95     dfs1(1);
 96     
 97     dfs2(1);
 98     
 99     dfs3(1);
100     
101     /*
102     for (int i = 1; i <= n; ++i)
103         printf("%f ", p[i]);
104     puts("");
105     
106     for (int i = 1; i <= n; ++i)
107         printf("%f ", f[i]);
108     puts("");
109     
110     for (int i = 1; i <= n; ++i)
111         printf("%d ", size[i]);
112     puts("");
113     */
114     
115     double ans = 0;
116     
117     for (int i = 1; i <= n; ++i)
118         if (size[i] > m)ans = std::max(ans, f[i]);
119         
120     printf("%f
", ans);
121 }

@Author: YouSiki

原文地址:https://www.cnblogs.com/yousiki/p/6235553.html