Tree Infection(CF)
阿新 • • 發佈:2022-04-12
簡而言之:
一棵樹,每秒鐘你要做兩個操作:
傳播:對於每個頂點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; }