Codeforces Round #781(C. Tree Infection)

Codeforces Round #781
C. Tree Infection
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

A tree is a connected graph without cycles. A rooted tree has a special vertex called the root. The parent of a vertex vv (different from root) is the previous to vv vertex on the shortest path from the root to the vertex vv. Children of the vertex vv are all vertices for which vv is the parent.

You are given a rooted tree with nn vertices. The vertex 11 is the root. Initially, all vertices are healthy.

Each second you do two operations, the spreading operation and, after that, the injection operation:

  1. Spreading: for each vertex vv, if at least one child of vv is infected, you can spread the disease by infecting at most one other child of vv of your choice.
  2. Injection: you can choose any healthy vertex and infect it.

This process repeats each second until the whole tree is infected. You need to find the minimal number of seconds needed to infect the whole tree.

Input

The input consists of multiple test cases. The first line contains a single integer tt (1t≤1e4) — the number of test cases. Description of the test cases follows.

The first line of each test case contains a single integer nn (2n2e5) — the number of the vertices in the given tree.

The second line of each test case contains n1n−1 integers p2,p3,,pnp2,p3,…,pn (1pin), where pipi is the ancestor of the ii-th vertex in the tree.

It is guaranteed that the given graph is a tree.

It is guaranteed that the sum of nn over all test cases doesn't exceed 2e5.

 

 

 

复制代码
 1 # include<iostream>
 2 # include<algorithm>
 3 # include<queue>
 4 # define int long long
 5 # define endl "\n"
 6 using namespace std;
 7 const int N = 1000050;
 8 int f[N],vis[N];
 9 
10 void solve(){
11     int n;
12     cin>>n;
13     for(int i = 1;i <= n;++i) f[i] = 0;
14     for(int i = 2;i <= n;++i){
15         int x;
16         cin>>x;
17         f[x]++;
18     }
19     int l = 1,r = n,res = n;
20     while(l <= r){
21         int mid = (l+r)>>1;
22         for(int i = 0;i <= n;++i) vis[i] = 0;
23         priority_queue<pair<int,int> > q;
24         
25         for(int i = 1;i <= n;++i) if(f[i]) q.push({f[i],i});
26         q.push({1,0});
27         for(int i = 1;i <= mid;++i){
28             if(q.empty()) break;
29             auto now = q.top();q.pop();
30             if(!vis[now.second]) now.first -=mid - i+1,vis[now.second] = 1;
31             else now.first--;
32             if(now.first > 0) q.push(now);
33         }
34         if(q.empty()) res = mid,r = mid-1;
35         else l = mid+1;
36     }
37     cout<<res<<endl;
38 }
39 
40 int tt;
41 signed main(){
42     ios::sync_with_stdio(false);
43     cin.tie(nullptr);
44     cout.tie(nullptr);
45     cin>>tt;
46     while(tt--){
47         solve();
48     }
49     
50     
51     return 0;
52 }
复制代码

  二分实在是精彩

根据题意将相同父节的个数进排序,每次对个数最多的进行操作

如果尚未被感染则选择注射,如果已经被注射过,则选择传播给相同父节点的子节点

通过priority_queue来进行排序,每次取对头进行操作,通过vis进行对节点(相同父节点)的判断是否被感染过

 

而二分的是操作次数(二分答案),有两种可能,如果操作次数内使得队列为空说明在当前操作次数可以满足全部感染,继续查找更小的操作次数

否则就不能满足全部感染,查找更大的操作次数

posted @   empty_y  阅读(157)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示