• C. Tree Infection(二分)


    Problem - 1665C - Codeforces

     

    一棵树是一个没有循环的连接图。一棵有根的树有一个特殊的顶点,叫做根。一个顶点v(不同于根)的父顶点是指从根到顶点v的最短路径上的前一个顶点。

    给你一棵有n个顶点的有根树。顶点1是根。最初,所有顶点都是健康的。

    每一秒钟你做两个操作,传播操作,之后是注入操作。

    传播:对于每个顶点,如果至少有一个v的孩子被感染,你可以通过感染你选择的v的最多一个其他孩子来传播疾病。
    注入:你可以选择任何健康的顶点并感染它。
    这个过程每秒重复一次,直到整个树被感染。你需要找到感染整棵树所需的最小秒数。

    输入
    输入由多个测试案例组成。第一行包含一个整数t(1≤t≤104)--测试案例的数量。测试用例的描述如下。

    每个测试用例的第一行包含一个整数n(2≤n≤2⋅105)--给定树中顶点的数量。

    每个测试用例的第二行包含n-1个整数p2,p3,...,pn(1≤pi≤n),其中pi是树中第i个顶点的祖先。

    可以保证给定的图是一棵树。

    保证所有测试案例的n之和不超过2⋅105。

    输出
    对于每个测试案例,你应该输出一个整数--感染整个树所需的最小秒数。

    例子
    inputCopy
    5
    7
    1 1 1 2 2 4
    5
    5 5 1 4
    2
    1
    3
    3 1
    6
    1 1 1 1 1
    输出拷贝
    4
    4
    2
    3
    4

    题解:
    首先我们要明确:

    只有同一个父节点的字节的才可以通过传播感染,子节点是无法传播到父节点的,所以父节点只能通过注入感染

    但是还有一个特例,1是没有父节点的,所以他只能通过注入感染

    所以初始cnt = 0

    对于传播感染,前提是父节点已经感染,

    然后就是二分

    最先开始传播感染的应该是字结点最多的,所以我们要排一下序

    每次check,x秒内是否可以全部感染完即可

    剩下一些细节在代码中有注释

    1. #include<iostream>
    2. #include<algorithm>
    3. #include<cstring>
    4. #include<string>
    5. #include<map>
    6. #include<vector>
    7. #include<queue>
    8. using namespace std;
    9. #define int long long
    10. //1 1 3 3 3
    11. int son[200050];
    12. int cnt;
    13. vector<int> v[200050];
    14. int check(int x)
    15. {
    16. int ans = 0;
    17. int k = 0;
    18. for(int i = 1,j = x- 1;i <= cnt;j --,i++)//被传播感染的结点,前提是有一个已经传染的父节点,所以先减1
    19. {
    20. ans += max(k,son[i] - j);
    21. }
    22. return x - cnt>= ans;//先注入感染的在这里有体现,减了cnt个注入感染的
    23. }
    24. void solve()
    25. {
    26. int n;
    27. cin >> n;
    28. for(int i = 1;i <= n;i++)
    29. v[i].clear();
    30. for(int i = 2;i <= n;i++)
    31. {
    32. int x;
    33. cin >> x;
    34. v[x].push_back(i);
    35. }
    36. cnt = 1;//由于1没有父节点,所以1肯定是要通过方式2感染的
    37. son[1] = 0;//单纯清空数组,无特殊含义
    38. for(int i = 1;i <= n;i++)
    39. {
    40. if(v[i].size())
    41. {
    42. son[++cnt] = v[i].size() - 1;//要开始传播感染,首先要注入感染一个
    43. }
    44. }
    45. sort(son+1,son+1+cnt,greater<>());
    46. int l = cnt,r = n;
    47. while(l <= r)
    48. {
    49. int mid = (l+r)/2;
    50. if(check(mid))
    51. {
    52. r = mid - 1;
    53. }
    54. else{
    55. l = mid + 1;
    56. }
    57. }
    58. cout<<l<<"\n";
    59. }
    60. signed main()
    61. {
    62. // ios::sync_with_stdio(false);
    63. // cin.tie(0);
    64. // cout.tie(0);
    65. int t = 1;
    66. cin >> t;
    67. while(t--)
    68. {
    69. solve();
    70. }
    71. }

  • 相关阅读:
    Google Earth Engine —— 隐形错误get获取元素后结果无法筛选(字符串转数字函数)
    博客要写得好,Emoji要用对!
    【Unity的HDRP下ShaderGraph实现权重缩放全息投影_(内附源码)】
    2021-05-14 Redis面试题 Redis持久化数据和缓存怎么做扩容?
    Java | 多线程综合练习
    halcon学习和实践(开篇)
    【java学习—八】==操作符与equals方法(2)
    网络安全(黑客)自学
    【前端设计模式】之模版方法模式
    【threejs教程8】threejs添加3D场景键盘控制
  • 原文地址:https://blog.csdn.net/m0_64158084/article/details/128074519