1 条题解

  • 0
    @ 2026-9-4 10:49:47

    分数二分+DFS。

    容易看出是 0-1 形二分。

    每次check里,记 f 表示以 f 为根的子树都烂了,因为注意到烂的一定是一棵子树所有的点。初始时所有叶子标记为 11

    在DFS 回溯的时候记录一下,对于一个节点,如果所有子树中坏点数量最多的那颗子树的坏点数量除以占比大于 pp,就可以令当前节点的 f =1=1

    然后最后记录一下 f=1f=1 的所有结点的子树大小的最大值,判断是否<=m

    然后就没了。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    vector<int> v[500005];
    int sz[500005];
    bool fl[500005];
    void pre_dfs(int now){
    	sz[now]=1;
    	for(int k:v[now]){
    		pre_dfs(k);
    		sz[now]+=sz[k];
    	}
    }
    double p;
    void dfs(int now){
    	fl[now]=0;
    	if(v[now].size()==0){
    		fl[now]=1;
    		return;
    	}
    	int maxx=0;
    	for(int k:v[now]){
    		dfs(k);
    		if(fl[k]) maxx=max(maxx,sz[k]);
    	}
    	if(maxx*1.000000/(sz[now]-1.000000)>p){
    		fl[now]=1;
    	} 
    	else{
    		fl[now]=0;
    	}
    }
    int n,m;
    bool check(double pw){
    	p=pw;
    	dfs(1);
    	int maxx=0;
    	for(int i=1; i<=n; i++){
    		maxx=max(maxx,fl[i]*1*sz[i]);
    	}
    	memset(fl,0,sizeof fl);
    	return maxx<=m;
    }
    signed main(){
        //cin.tie(0);
        //ios::sync_with_stdio(false);
        cin>>n>>m;
        for(int i=2; i<=n;i++){
        	int vv;
        	scanf("%d",&vv);
        	v[vv].push_back(i);
    	}
    	pre_dfs(1);
        double l=0.000000,r=1.000000;
        while(fabs(r-l)>1e-5){
        	double mid=(l+r)/2.0;
        	if(check(mid)) r=mid;
        	else l=mid;
    	}
    	printf("%.6lf",l);
        return 0;
    }
    

    信息

    ID
    727
    时间
    1000ms
    内存
    256MiB
    难度
    8
    标签
    递交数
    36
    已通过
    5
    上传者