BZOJ4726: [POI2017]Sabota?

$n \leq 500000$的树,开始有一个点是坏的,如果一个子树中坏点比例(不包括根节点)超过x那这整棵子树就会变坏,问最坏情况下不超过$K$个坏点的情况下$x$最小是多少。

被坑成傻逼。。

可以发现最坏情况下一开始的坏点一定是某个叶子。

首先容易看出的做法是二分完直接dp一次验证是否超过$K$,没想到log居然过不了5e5。

百度上有个大爷:“这不是二分+dp吗,不知道为啥过的人那么少。”妈耶我常数bigbig。。算了反正正解是O(n)的学一学。

$f(i)$--子树$i$中,要使$i$不被孩子污染,$x$至少是多少。$f(i)=max(min(f(j),\frac{size_j}{size_i-1}))$。最后把子树大小超过$K$的子树的$f$取个Max。

 1 #include<stdio.h>
 2 #include<string.h>
 3 //#include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 #define LL long long
 8 int qread()
 9 {
10     char c; int s=0,t=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (t=-1);
11     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*t;
12 }
13 
14 //
15 
16 int n,K;
17 #define maxn 500011
18 struct Edge{int to,next;}edge[maxn<<1]; int first[maxn],le=2;
19 void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;}
20 
21 double f[maxn]; int fa[maxn],size[maxn];
22 
23 int main()
24 {
25 //    freopen("sab97.in","r",stdin);
26     n=qread(); K=qread();
27     for (int i=2;i<=n;i++) fa[i]=qread(),in(fa[i],i);
28     for (int i=1;i<=n;i++) size[i]=1;
29     for (int i=n;i;i--) size[fa[i]]+=size[i];
30     double ans=0;
31     for (int x=n;x;x--)
32     {
33         f[x]=0;
34         if (first[x]==0) f[x]=1;
35         else for (int i=first[x];i;i=edge[i].next)
36         {
37             Edge &e=edge[i];
38             f[x]=max(f[x],min(f[e.to],size[e.to]*1.0/(size[x]-1)));
39         }
40         if (size[x]>K) ans=max(ans,f[x]);
41     }
42     printf("%.9f\n",ans);
43     return 0;
44 }
View Code

 

posted @ 2018-05-25 14:34  Blue233333  阅读(161)  评论(0编辑  收藏  举报