CF #781 Div. 2 C. Tree Infection
作者:互联网
题面翻译:
给出一个有 n 个顶点的有根树,节点 1 为根节点。一开始,所有节点都是 健康的。每秒将进行 两次操作,先开始传染 spreading,然后进行注射 injection
- spreading: 对于每一个节点 v,如果它有一个已感染的子女,你可以选择对 v 的其他子女进行感染
- injecting:选择任意一个健康节点进行感染
这个过程每秒都重复执行直到整棵树被感染。你需要找出感染整棵树需要的最小秒数。
思路:
贪心、堆
首先可以发现,一个节点的子女 和 另一个节点的子女 是独立的。那我们可以按照父节点进行分组,就是所有兄弟节点在同一个组内,我们记组数为 m 每个组的节点数量为ci
因为是独立的,那么说明至少需要进行 m 次注射操作。每秒只能注射一次,所以同时 m 秒也是下限。
然后我们考虑怎么节省时间。第一秒过后,我们注射一个节点之前,可以直接感染前面注射点的健康兄弟节点。然后等到所有分组都被有节点被注射后(第 m 秒结束)。我们就看看有没有哪个组还有很多健康节点,有就去进行注射操作节省时间。
那说明我们要尽量减少 m 秒之后花费的时间,即,尽量在第 m 秒结束之前感染尽可能多的节点。
可以发现,在第 j 秒注射的组,在到第 m 秒结束时就能总共感染 min(m - j + 1, ci) 的节点。可以看出如果一个组已经全感染了,那他就对节省时间没有贡献了。那么进行贪心,把组按照节点个数从大到小排序,尽量让节点数多的减掉更多,贡献就是最大的。
考虑 m 秒以后。此时存活的组每秒都会减少一个健康节点,注射可以给特定组减多一个健康节点。直到健康节点最多的那个组也少于 3 个,那么下一秒它也全部感染了。题目整颗树节点最多2×105,过程是 O(n * log2n) 的,可以直接模拟。
实现:
我们用数组去记录每个节点的子女数量,就完成了分组。m 秒之后的部分,全部减一不会影响到堆的结构,直接在外面记录减了多少就行。注射操作用一个数组记录,下标 i 的位置就表示第 i 组注射了多少,进堆的时候排序关键字就是 (原数量(m 秒之后的) - 注射次数)。
代码实现#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAX_N = 2e5;
int chd[MAX_N + 1];
vector<int> grp;
int t[MAX_N + 1];
struct cmp
{
bool operator()(int a, int b) const
{
return grp[a] + t[a] < grp[b] + t[b];
}
};
priority_queue<int, vector<int>, cmp> q;
void solve()
{
memset(chd, 0, sizeof(chd));
memset(t, 0, sizeof(t));
while (q.size()) q.pop();
grp.clear();
int n;
scanf("%d", &n);
chd[0] = 1;
for (int i = 2; i <= n; ++i)
{
int pi;
scanf("%d", &pi);
++chd[pi];
}
for (int i = 0; i <= n; ++i)
{
if (chd[i]) grp.push_back(chd[i]);
}
sort(grp.begin(), grp.end(), greater<int>());
n = grp.size();
for (int i = 0; i != n; ++i)
{
// after all groups injected;
grp[i] -= n - i;
if (grp[i] > 0) q.emplace(i);
}
int exa = 0;
while (q.size())
{
int i = q.top();
q.pop();
++exa;
int will = grp[i] + t[i] - exa;
if (will <= 0)
{
if (will < 0) --exa;
break;
}
--t[i]; //inj
if (will >= 1) q.push(i);
}
printf("%d\n", exa + n);
}
int main(void)
{
int cases;
scanf("%d", &cases);
while (cases--) solve();
return 0;
}
标签:chd,grp,int,感染,Tree,CF,Div,节点,注射 来源: https://www.cnblogs.com/julic20s/p/cf-781-2c.html