P5958 [POI2017]Sabotaż

P5958 [POI2017]Sabotaż

分析

一看到,就知道是一个树形dp题目了。

关键在于状态的定义

f[i]表示使得i变黑的最大x

从而我们可以知道,f[i]的大小只与f[soni]和soni的大小有关

那么我们用sum(i)表示以i为根节点的子树的大小,sum(i)是需要提前用dfs预处理的

显然ii被染黑仅必须满足以下两种情况:

  1. f[soni]>x,即表示I的某颗子树被全部染黑
  2. sum(soni)/(sum[i]-1)>x,表示子树i的染黑能使得i被染黑

根据以上可以推出

\[f[i] = max(f[i],min(f[son[i]],sum[i]/(sum[i]-1))) \]

其中有一些细节需要注意

  1. 若a为子节点,则显然f[a] = 1
  2. 对于ans当sum<k时是不需要考虑的,因为他显然合法,就算它被染黑也无所谓
  3. 因此显然,ans=max(ans,f[a]),当且仅当sum[a]>k

AC_code

#include<bits/stdc++.h>
using namespace std;
const int N  = 5e5 + 10;
int h[N],e[N],ne[N],idx;
int sz[N];
int n,k;
double f[N],ans;

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

void dfs(int u)
{
    sz[u] = 1;
    for(int i=h[u];~i;i=ne[i])
    {
        int j = e[i];
        dfs(j);
        sz[u] += sz[j];
    }
    if(h[u]==-1){
        f[u] = 1;
        return ;
    }
    for(int i=h[u];~i;i=ne[i])
    {
        int j = e[i];
        f[u] = max(f[u],min(f[j],(double)sz[j]/(sz[u]-1)));
    }
    if(sz[u]>k) ans = max(ans,f[u]);
}

int main()
{
    cin>>n>>k;
    memset(h,-1,sizeof h);
    for(int i=2;i<=n;i++) 
    {
        int x;cin>>x;
        add(x,i);
    }
    dfs(1);
    printf("%.10lf",ans);
    return 0;
}
posted @ 2022-03-18 21:08  艾特玖  阅读(28)  评论(0)    收藏  举报