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;
}
posted @ 2022-04-12 11:35  wzx_believer  阅读(96)  评论(0编辑  收藏  举报