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;
}
posted @ 2025-04-30 11:10  特别之处  阅读(20)  评论(0)    收藏  举报