1. 程式人生 > 其它 >Tree Infection(CF)

Tree Infection(CF)

簡而言之:
一棵樹,每秒鐘你要做兩個操作:

傳播:對於每個頂點v,如果v的至少一個孩子被感染,你可以通過感染你選擇的v的至多一個其他孩子來傳播疾病。

注射:你可以選擇任何一個健康的頂點,感染它。

求最少的次數

分析:很明顯只關於一個節點兒子的個數為多少

如果有x個點有兒子 那麼至少需要x次 並且很明顯兒子數量越多我們就要越先感染

按照兒子個數排序從小到大 第一輪感染剩下的兒子分別為 sz[u]-i

第一輪感染完成後 保證了每個節點的兒子都有病原體 剩下的問題就是我們感染操作和傳播操作要同時進行

模型變為 一個數列 每一秒 數列每個大於0的數都減一 此外每一秒你可以對一個元素額外減一

我們從大到小列舉還需要的次數即可 這道題難點就在後面這個點

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=2e5+5;
int n,x,T;
int sz[maxn];
vector<int>Q,S;
int main(){
	cin>>T;
	while(T--){
		cin>>n;
		memset(sz,0,sizeof(sz));
		Q.clear();S.clear();
		Q.push_back(1);
		for(int i=2;i<=n;i++)
		scanf("%d",&x),sz[x]++;
		for(int i=1;i<=n;i++)
		if(sz[i])Q.push_back(sz[i]);
		sort(Q.begin(),Q.end());
		int cntt=Q.size();
		for(int i=0;i<cntt;i++)
		if(Q[i]-i-1>0)S.push_back(Q[i]-i-1);
		int cnt=S.size();
		if(cnt){
		sort(S.begin(),S.end());
		int res,j=cnt-1;
		int tot=0;
		for(int i=S[cnt-1];i>=1;i--){
			while(j>=0&&S[j]>i)j--;
			tot+=cnt-1-j;
			if(tot<=i)res=i;
			else break;
		}		 
		cout<<res+cntt<<endl;
		}else cout<<cntt<<endl;
	}
     return 0;
}