P5958 [POI2017]Sabotaż
分析
一看到,就知道是一个树形dp题目了。
关键在于状态的定义
f[i]表示使得i变黑的最大x
从而我们可以知道,f[i]的大小只与f[soni]和soni的大小有关
那么我们用sum(i)表示以i为根节点的子树的大小,sum(i)是需要提前用dfs预处理的
显然ii被染黑仅必须满足以下两种情况:
- f[soni]>x,即表示I的某颗子树被全部染黑
- sum(soni)/(sum[i]-1)>x,表示子树i的染黑能使得i被染黑
根据以上可以推出
\[f[i] = max(f[i],min(f[son[i]],sum[i]/(sum[i]-1)))
\]
其中有一些细节需要注意
- 若a为子节点,则显然f[a] = 1
- 对于ans当sum<k时是不需要考虑的,因为他显然合法,就算它被染黑也无所谓
- 因此显然,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;
}

浙公网安备 33010602011771号