本文总字数:1592,阅读预计需要:4分钟
一种神奇套路:对答案根分,根分的依据是链的长度和答案大致是一个成反比的关系。
考虑确定了 怎么做。因为一个点只能在一条链里,所以 dfs 的时候如果能拼成一条链就一定会拼成一条链,不然就把贡献传给父亲继续尝试。
对于 比较小的时候可以暴力计算。对于 较大的情况,发现答案一定非严格单减,并且递减的幅度越来越小。所以对于 比较大的情况,可以通过枚举答案,二分找出答案对应的区间。
设块长为 ,对于 暴力计算, 枚举答案不会超过 ,复杂度 ,块长取 可以通过此题。
一点卡常技巧: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');
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现