Tree Infection(CF)
简而言之:
一棵树,每秒钟你要做两个操作:
传播:对于每个顶点v,如果v的至少一个孩子被感染,你可以通过感染你选择的v的至多一个其他孩子来传播疾病。
注射:你可以选择任何一个健康的顶点,感染它。
求最少的次数
分析:很明显只关于一个节点儿子的个数为多少
如果有x个点有儿子 那么至少需要x次 并且很明显儿子数量越多我们就要越先感染
按照儿子个数排序从小到大 第一轮感染剩下的儿子分别为 sz[u]-i
第一轮感染完成后 保证了每个节点的儿子都有病原体 剩下的问题就是我们感染操作和传播操作要同时进行
模型变为 一个数列 每一秒 数列每个大于0的数都减一 此外每一秒你可以对一个元素额外减一
我们从大到小枚举还需要的次数即可 这道题难点就在后面这个点
#include
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=2e5+5;
int n,x,T;
int sz[maxn];
vectorQ,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;i0)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<