1. 程式人生 > 其它 >CF #781 (Div. 2), (C) Tree Infection

CF #781 (Div. 2), (C) Tree Infection

Problem - C - Codeforces

 

 

 

 

Example input
5
7
1 1 1 2 2 4
5
5 5 1 4
2
1
3
3 1
6
1 1 1 1 1
output
4
4
2
3
4

 

 

題意

n個點組成一個樹, 1作為根節點, 輸入第2~n個數的父節點序號, 問最少幾次感染操作會使得整棵樹全被感染, 每次兩種感染操作都會進行1. 感染: 單獨感染一個點  2.擴散: 如果某一父節點的孩子有感染的, 則在此父節點下的一個孩子也可以被感染

題解

開始想的按孩子數多少從小到大排序, 依次操作 --> 不行, 因為若出現多個父節點的孩子數一樣且很多的時候, 不可以挨個依次操作, 每個孩子堆 都得先感染一個使得操作2不被浪費

正解: 也是先按孩子數從小到大排序, 孩子數q[i]減去每個孩子堆只會先單獨感染一個點到最後感染的個數, 即q[i]-i-2,  2=根節點1感染一次+i的孩子第一次感染, 最後放到堆裡, 每次最大的取出, 最大的-1再壓進去, 直到小於等於cnt

貼程式碼

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
typedef pair<double,double> PII;
const int N = 2e5+10;
int mp[N], sum[N];

int main()
{
    
int t; cin >> t; while(t --) { int n, times=1; cin>>n; for(int i = 0; i <= n; i ++) mp[i] = 0, sum[i] = 0; for(int i = 1; i < n; i ++) { int a; cin >> a; if(mp[a]==0)times++; mp[a]
++;//i的孩子數 } vector<int> q; for(int i = 1; i <= n; i ++) if(mp[i]) q.push_back(mp[i]); sort(q.begin(), q.end()); priority_queue<int> sum; for(int i = 0; i < q.size(); i ++) if(q[i]-1-i > 0) sum.push(q[i]-2-i); int cnt = 0; while(sum.size()) { int tt = sum.top(); sum.pop(); if(tt>cnt) { sum.push(tt-1); cnt ++; } else break; } cout << times+cnt<<endl; } return 0; }