[ POI 2017 ] Sabota?

Description

题目链接

Solution

因为一个节点染黑了子树就都被染黑了,所以最后染黑的点集必然是一棵子树。

可以得出的结论是,如果被染黑的节点在节点 \(a\) 的子树中,而 \(a\) 没有被染黑,那么 \(a\) 的任意次祖先都不会被染黑。

从另一个角度理解就是,染黑的节点在 \(a\) 子树中的大小占比不超过 \(x\) ,那么在 \(a\) 的祖先里占比更小,显然也超不过 \(x\)

\(f[i]\) 表示节点 \(i\) 不被染黑的最小的 \(x\) ,那么合法情况为:

子节点不染黑(上述结论),或子节点大小在儿子中占比不超过 \(x\)

特殊的,对于叶节点,最差的情况显然是它被染黑,所以 \(f[u]=1\)

因此转移方程为

\[f[i]=\max_{v\in son[u]} \bigg\{\min\bigg(f[v], \frac{size[v]}{size[u] - 1}\bigg)\bigg\} \]

注意到大小不超过 \(k\) 的子树染不染黑没关系,所以

\[ans = \max_{size[u]>k}\{f[u]\} \]

#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define N 500005
using namespace std;
 
inline int rd() {
  int x = 0;
  char c = getchar();
  while (!isdigit(c)) c = getchar();
  while (isdigit(c)) {
    x = x * 10 + (c ^ 48); c = getchar();
  }
  return x;
}
 
double ans, f[N];
 
int n, m, tot, hd[N], sz[N];
 
struct edge{int to, nxt;} e[N << 1];
 
inline void add(int u, int v) {
  e[++tot].to = v; e[tot].nxt = hd[u]; hd[u] = tot;
  e[++tot].to = u; e[tot].nxt = hd[v]; hd[v] = tot;
}
 
void dfs(int u, int fa) {
  sz[u] = 1;
  for (int i = hd[u], v; i; i = e[i].nxt)
    if ((v = e[i].to) != fa) {
      dfs(v, u); sz[u] += sz[v];
    }
  if (sz[u] == 1) {f[u] = 1.0; return;}
  for (int i = hd[u], v; i; i = e[i].nxt)
    if ((v = e[i].to) != fa)
      f[u] = max(f[u], min(f[v], (double)sz[v] / (sz[u] - 1)));
  if (sz[u] > m) ans = max(ans, f[u]);
}
 
int main() {
  n = rd(); m = rd();
  for (int i = 2; i <= n; ++i) add(i, rd());
  dfs(1, 0);
  printf("%.10lf\n", ans);
  return 0;
}
posted @ 2019-03-29 11:30  SGCollin  阅读(...)  评论(...编辑  收藏