[POI2017]Sabota【观察+树形Dp】

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);
}

原文地址:https://www.cnblogs.com/Tieechal/p/11522639.html

时间: 2024-08-08 15:16:55

[POI2017]Sabota【观察+树形Dp】的相关文章

BZOJ_4726_[POI2017]Sabota?_树形DP

Description 某个公司有n个人, 上下级关系构成了一个有根树.其中有个人是叛徒(这个人不知道是谁).对于一个人, 如果他 下属(直接或者间接, 不包括他自己)中叛徒占的比例超过x,那么这个人也会变成叛徒,并且他的所有下属都会变 成叛徒.你要求出一个最小的x,使得最坏情况下,叛徒的个数不会超过k. Input 第一行包含两个正整数n,k(1<=k<=n<=500000). 接下来n-1行,第i行包含一个正整数p[i+1],表示i+1的父亲是p[i+1](1<=p[i+1]&

[bzoj4726][POI2017][Sabota?] (树形dp)

Description 某个公司有n个人, 上下级关系构成了一个有根树.其中有个人是叛徒(这个人不知道是谁).对于一个人, 如果他 下属(直接或者间接, 不包括他自己)中叛徒占的比例超过x,那么这个人也会变成叛徒,并且他的所有下属都会变 成叛徒.你要求出一个最小的x,使得最坏情况下,叛徒的个数不会超过k. Input 第一行包含两个正整数n,k(1<=k<=n<=500000). 接下来n-1行,第i行包含一个正整数p[i+1],表示i+1的父亲是p[i+1](1<=p[i+1]&

【BZOJ4726】[POI2017]Sabota? 树形DP

[BZOJ4726][POI2017]Sabota? Description 某个公司有n个人, 上下级关系构成了一个有根树.其中有个人是叛徒(这个人不知道是谁).对于一个人, 如果他 下属(直接或者间接, 不包括他自己)中叛徒占的比例超过x,那么这个人也会变成叛徒,并且他的所有下属都会变 成叛徒.你要求出一个最小的x,使得最坏情况下,叛徒的个数不会超过k. Input 第一行包含两个正整数n,k(1<=k<=n<=500000). 接下来n-1行,第i行包含一个正整数p[i+1],表示

BZOJ 4726 POI 2017 Sabota? 树形DP

4726: [POI2017]Sabota? Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 128  Solved: 49[Submit][Status][Discuss] Description 某个公司有n个人, 上下级关系构成了一个有根树.其中有个人是叛徒(这个人不知道是谁).对于一个人, 如果他下属(直接或者间接, 不包括他自己)中叛徒占的比例超过x,那么这个人也会变成叛徒,并且他的所有下属都会变成叛徒

Vijos 1523 贪吃的九头龙 【树形DP】

贪吃的九头龙 背景 安徽省芜湖市第二十七中学测试题 NOI 2002 贪吃的九头龙(dragon) Description:OfficialData:OfficialProgram:Converted by JackDavid127 描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落. 有一天,有M个脑袋的九头龙看到一棵长有N个果子的果树,喜出望外,

BZOJ 2286 消耗战 (虚树+树形DP)

给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<=500000) 考虑树形DP,我们令mn[i]表示i节点无法与1节点相连切除的最小权值.显然有mn[i]=min(E(fa,i),mn[fa]).大致就是i到1的简单路径上的最小边.我们对于每个询问.把询问的点不妨称为关键点.令dp[i]表示i节点不能与子树的关键点连接切掉的最小权值.那么有,如果son[i]

POJ 2057 The Lost House 经典树形DP+贪心

题意:链接 方法:树形DP+贪心 解析:这是一道好题. 好首先要明确这题求的是什么? 名义上是期望值,而实际上就是找一条路径.什么路径呢?从根节点走遍所有的叶子节点所花费步数最短的路径. 明确了题意后该怎么做呢? 首先看我们需要什么? 目前有个根节点,我们需要知道从他向一个分支走,失败步数是多少,成功步数是多少? 那么怎么维护我们需要的东西呢? 首先我们先给他们起个名:suc,fai; 其次再给一个节点的叶子节点的个数起个名:son 起名完事之后我们就要更新了. 先谈叶子节点,显然叶子节点的su

有线电视网(树形dp)

有线电视网 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点.从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号的费用总和.现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪些用户提供信号而不给哪些用户提供信号.写一个程序找出一个方案使得有线电视网在不亏本的情况下使观看转播的用户尽可能多.2≤N≤3000. 关

树形dp 结论题 bzoj5024 [Jsoi2010]游戏

http://www.lydsy.com/JudgeOnline/problem.php?id=5024 首先吐槽一下题面是有错误的 那一个"或" 应该改成"," 这道题目条件是非常绕的 先看一个简化的问题 我们对于\(u\), \(v\) 如果\(u-v\)是良的 那么染成白色 否则染成黑色 问题转化成一个经典问题 给定一个完全图 求同色三角形的个数 做法就是考虑非同色三角形的个数 找角的个数\(jiao\) 答案就是\(C_n ^ 3 - jiao / 2\)