题意分析
最坏情况一定是这个叛徒是叶子结点,这样他才有更大的概率来影响他的上级,比如你使一个子树都变为叛徒,肯定比仅有这个子树的根节点是叛徒影响力更大。
叛徒集体一定是一棵子树,因此我们选用深搜,递归来树形 \(DP\) ,以此维护相关信息。
\(f_i\) 表示 \(i\) 不是叛徒的最小 \(x\) , \(s_i\) 表示子树的大小。
对于叶子结点,它的 \(f\) 显而易见应为1,因此可以初始化所有的 \(f\) 为1。
对于每个节点,枚举它的子节点,若要满足以该节点为根的子树不整体受影响,它需要同时满足以下任一条件,满足儿子不受影响,满足儿子为根的子树大小占比不对自己产生影响。
转移式。
f[u]=max(f[u],min(f[v],(double)s[v]/(s[u]-1)));
处理完每个节点后,如果它的子树大小大于限制的 \(k\) ,我们就需要将它的 \(f\) 纳入考虑范围之内,以它更新 \(ans\)。
最后输出即可,考虑精度,输出八位小数。
代码
#include<bits/stdc++.h>
using namespace std;
int s[500005],n,k,head[500005],tot;
double f[500005],ans;
struct node{
int to,next;
}a[500005];
void dfs(int u,int fr){
s[u]=1;
for(int i=head[u];i;i=a[i].next){
int v=a[i].to;
if(v==fr)continue;
dfs(v,u);
s[u]+=s[v];
}
for(int i=head[u];i;i=a[i].next){
int v=a[i].to;
if(v==fr)continue;
f[u]=max(f[u],min(f[v],(double)s[v]/(s[u]-1)));
if(f[u]==1)f[u]=min(f[v],(double)s[v]/(s[u]-1));//特判,否则答案恒为1
}
if(s[u]>k)ans=max(ans,f[u]);//更新
}
int main()
{
cin>>n>>k;
for(int i=2;i<=n;i++){
int x;
cin>>x;
a[++tot].to=i;
a[tot].next=head[x];
head[x]=tot;
}
for(int i=1;i<=n;i++)f[i]=1;
dfs(1,0);
printf("%.8lf",ans);
}