CF1039D You Are Given a Tree 题解
首先,我们有一个简单的\(O(n)\)的贪心来写某一个\(k\)的答案,我们考虑根号分支,前头用\(O(Bn)\)的复杂度计算答案,后头最多只有\(\frac{n}{B}\)种值,我们每一次可以二分出某一个值对应的区间,复杂度是\(O(n \log_2{n})\),那么合并一下复杂度就是\(O(Bn+\frac{n^2 \log_2{n}}{B})\),发现\(B\)取值\(\sqrt{n \log_2{n}}\)复杂度可以达到\(O(n\sqrt{n\log_2{n}})\),常数略大,把递归改成dfn序遍历即可,我跑的比较慢,是\(4s\),但是相对于\(7s\)的时限还是绰绰有余的。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int maxx[maxn],cmax[maxn],ge,ans[maxn],x,y,len,l,r,n,jie,cnt,dfn[maxn],ll,rr;
vector<int>tu[maxn],t[maxn];
inline void dfs(int q,int w){
for(int i=0;i<tu[q].size();i++){
if(tu[q][i]!=w){
t[q].push_back(tu[q][i]);
dfs(tu[q][i],q);
}
}
cnt++;
dfn[cnt]=q;
return;
}
int check(int q){
ge=0;
for(int ii=1;ii<=n;ii++){
int i=dfn[ii];
maxx[i]=cmax[i]=0;
for(int j=0;j<t[i].size();j++){
if(maxx[t[i][j]]>maxx[i]){
cmax[i]=maxx[i];
maxx[i]=maxx[t[i][j]];
}
else{
cmax[i]=max(cmax[i],maxx[t[i][j]]);
}
}
if(maxx[i]+cmax[i]+1>=q){
ge++;
maxx[i]=0;
}
else{
maxx[i]++;
}
}
return ge;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<n;i++){
cin>>x>>y;
tu[x].push_back(y);
tu[y].push_back(x);
}
dfs(1,0);
len=sqrt(n*log2(n));
len=min(len,n);
for(int i=1;i<=len;i++){
ans[i]=check(i);
}
r=len;
for(int i=n/len;i>=1;i--){
l=r+1;
r=l-1;
ll=l;
rr=n;
while(ll<=rr){
int mid=(ll+rr)/2;
if(check(mid)==i){
r=mid;
ll=mid+1;
}
else{
rr=mid-1;
}
}
for(int j=l;j<=r;j++){
ans[j]=i;
}
}
for(int i=1;i<=n;i++){
cout<<ans[i]<<'\n';
}
return 0;
}
浙公网安备 33010602011771号