[POI2017]Sabota【观察+树形Dp】
2024-09-06 01:54:42
Online Judge:Bzoj4726
Label:观察,树形Dp,水题
题目描述
某个公司有n个人, 上下级关系构成了一个有根树。公司中出了个叛徒(这个人不知道是谁)。
对于一个人, 如果他下属(直接或者间接, 不包括他自己)中叛徒占的比例超过x,那么这个人也会变成叛徒,并且他的所有下属都会变成叛徒。
你要求出一个最小的x,使得最坏情况下,叛徒的个数不会超过k。
输入
第一行包含两个正整数n,k(1<=k<=n<=500000)。
接下来n-1行,第i行包含一个正整数p[i+1],表示i+1的父亲是\(p[i+1]\)(1<=p[i+1]<=i)。
输出
输出一行一个实数x,误差在\(10^{-6}\)以内都被认为是正确的。
样例
Input
9 3
1
1
2
2
2
3
7
3
Output
0.6666666667
Hint
当x取2/3时,最坏情况下3,7,8,9都是叛徒,超过了k=3。
答案中的x实际上是一个无限趋近于2/3但是大于2/3的数。
题解
看样例知道实际上是求一个转变的临界值。
观察一下发现,要叛变就是整个子树一起叛变,而且因为只选了一个叶子节点做叛徒,所以只会有这唯一一棵树叛变——不会出现多棵不相关的子树同时叛变。
那么我们只需要算出以每个点为根的子树叛变时所需的最大叛变比例\(lim[i]\)即可。上面这个定义有点繁琐,本质是比例\(lim\)调大,子树叛变越难。我们就是求一个最大值,使得在这个比例下,子树刚好叛变,如果提高一点就叛变不了了。
求\(lim\)的方法类似树形dp。
最后统计时的代码如下,其中\(siz\)表示子树大小。求其中的最大值,因为比例达到这个最大值时,这些\(siz>k\)的子树都叛变不了(如果叛变了就不合法了)。
double ans=0;
for(int i=1;i<=n;i++)if(siz[i]>k)ans=max(ans,lim[i]);
printf("%.7f",ans);
完整代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
vector<int>e[N];
int n,k,siz[N];
double lim[N];//i的子树中叛变,能让i也叛变的最大k值
void dfs(int x){
siz[x]=1;
for(int i=0;i<e[x].size();i++)dfs(e[x][i]),siz[x]+=siz[e[x][i]];
if(siz[x]==1)lim[x]=1.0;
for(int i=0;i<e[x].size();i++){
int y=e[x][i];
lim[x]=max(lim[x],min(lim[y],1.0*siz[y]/(siz[x]-1.0)));
}
}
int main(){
scanf("%d%d",&n,&k);
for(int i=2,u;i<=n;i++){
scanf("%d",&u);
e[u].push_back(i);
}
dfs(1);
double ans=0;
for(int i=1;i<=n;i++)if(siz[i]>k)ans=max(ans,lim[i]);
printf("%.7f",ans);
}
最新文章
- 【Win 10应用开发】延迟加载图片的另一种方法
- shell-引号
- Leetcode 235 Lowest Common Ancestor of a Binary Search Tree 二叉树
- jQuery formValidator表单验证插件常见问题
- QListWidget特别简单,但有两种添加item的方式
- 【转】HashMap的工作原理
- eclispe输入@注解时提示所有注解的设置
- Jersey(1.19.1) - XML Support
- NodeJS+ExpressJS+SocketIO+MongoDB应用模板
- 初入 Spring.net
- 任何时候都适用的20个C++技巧
- 房上的猫:while循环与do-while循环,debug的调试运用
- QC API全系列揭秘之Test Execution操作(全网首发)
- (一)CentOS6.3安装Hadoop2.6.5
- ES5-ES6-ES7_Generator 函数
- 支付宝WAP支付总结
- HDU 1385 Minimum Transport Cost (输出字典序最小路径)【最短路】
- python全局变量
- php base64上传图片
- Deploy to container Plugin插件发布配置