$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 ",ans); 43 return 0; 44 }