1. 程式人生 > 其它 >Codeforces Round #781(C. Tree Infection)

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進行對節點(相同父節點)的判斷是否被感染過

 

而二分的是操作次數(二分答案),有兩種可能,如果操作次數內使得佇列為空說明在當前操作次數可以滿足全部感染,繼續查詢更小的操作次數

否則就不能滿足全部感染,查詢更大的操作次數