CF1039D You Are Given a Tree

CF1039D You Are Given a Tree

本文总字数:1592,阅读预计需要:4分钟

CF1039D You Are Given a Tree

更好的阅读体验

一种神奇套路:对答案根分,根分的依据是链的长度和答案大致是一个成反比的关系。

考虑确定了 k 怎么做。因为一个点只能在一条链里,所以 dfs 的时候如果能拼成一条链就一定会拼成一条链,不然就把贡献传给父亲继续尝试。

对于 k 比较小的时候可以暴力计算。对于 k 较大的情况,发现答案一定非严格单减,并且递减的幅度越来越小。所以对于 k 比较大的情况,可以通过枚举答案,二分找出答案对应的区间。

设块长为 B,对于 kB 暴力计算,k>B 枚举答案不会超过 nB,复杂度 O(Bn+n2Blogn),块长取 1000 可以通过此题。

一点卡常技巧:dfs 的次数非常多,所以可以先 dfs 一遍,之后按照 dfn 序扫一遍即可。

	int n,cnt,ans,bl,len,tot,maxn[100010],maxm[100010],up[100010],a[100010],fin[100010],head[100010],to[200010],nex[200010];
	inline void add(int x,int y){to[++cnt]=y,nex[cnt]=head[x],head[x]=cnt;}
	void dfs0(int k,int fa)
	{
		a[++tot]=k,up[k]=fa;
		for(int i=head[k];i;i=nex[i])if(to[i]!=fa)dfs0(to[i],k); 
	}
	void dfs()
	{
		for(int i=n;i>=1;--i)
		{
			int now=a[i];maxn[now]=maxm[now]=0;
			for(int j=head[now];j;j=nex[j])
			{
				if(to[j]==up[now])continue;
				int t=maxn[to[j]];
				if(t>=maxn[now])maxm[now]=maxn[now],maxn[now]=t;
				else Mmax(maxm[now],t);
			}
			if(maxn[now]+maxm[now]+1>=len)++ans,maxn[now]=0;
			else ++maxn[now];
		}
	}
    inline void mian()
    {
    	read(n),bl=1000;int x,y;
    	for(int i=1;i<n;++i)read(x,y),add(x,y),add(y,x);
    	dfs0(1,0);
    	for(int i=1;i<=bl;++i)len=i,ans=0,dfs(),fin[i]=ans;
    	int tt=ans;
    	for(int i=0,last=n+1;i<=tt;++i)
    	{
    		int l=bl+1,r=last,mid;
    		while(l<r)
    		{
    			len=mid=l+((r-l)>>1),ans=0,dfs();
    			if(ans>i)l=mid+1;
    			else r=mid;
			}
			for(int j=l;j<last;++j)fin[j]=i;
			last=l;
		}
		for(int i=1;i<=n;++i)write(fin[i],'\n');
	}
posted @   WrongAnswer_90  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现

This blog has running: 562 days 8 hours 45 minutes 57 seconds

点击右上角即可分享
微信分享提示