题解 P5958 [POI2017]Sabota?

题意分析

最坏情况一定是这个叛徒是叶子结点,这样他才有更大的概率来影响他的上级,比如你使一个子树都变为叛徒,肯定比仅有这个子树的根节点是叛徒影响力更大。

叛徒集体一定是一棵子树,因此我们选用深搜,递归来树形 \(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);
}

题解 P5958 [POI2017]Sabota?

上一篇:行政强制法 思维导图


下一篇:随机现象与随机变量