CF1039D You Are Given a Tree
题目大意
给出一棵个节点的树,对于~间的每一个数,你需要求出: 最多能选出多少条互不相交的路径,使得每条路径的长度都为。
思路
首先思考暴力的做法。就是贪心+树形dp,把整个树一次,对于每个节点考虑它子节点的最长链和次长链。如果最长链+次长链+,那么就说明它子节点的最长链和次长链通过那个子节点连起来形成的链可以满足长度大于等于,答案+。
那么为什么满足条件就一定要先把它们连起来呢?因为由于当前存在了一条满足要求的链,如果不计入答案,把最长链往上传,那么最多对答案也只有的贡献。所以先连起来可能会更优。这样时间复杂度就是。
之后就用分治优化。设分治节点为t,对于第一段直接用暴力求解,时间复杂度就是,对于第二段,因为答案只会在~这个范围内,而且是单调不升的,相同答案的k值肯定是连在一起的,所以可以考虑从左往右扫一遍,每次用二分出答案相同的一段,这样时间最多也就 。所以当t取时,时间复杂度最小,为。
当然,取会更容易理解,虽然时间没有= 快,但只要我们优化一下,去掉的过程,记录序,通过循环以达到的目的,也是可以过的。
所以我也把这个小优化也加到了我的代码里。
代码

#include<bits/stdc++.h> using namespace std; int n,q,x,y,head[200002],Fa[100001],dfsx[100001],f[100001],cnt=0,tot=0,t,l,r,mid; struct node{ int nxt,to; }e[200002]; void add(int x,int y){ e[++cnt].nxt=head[x]; e[cnt].to=y; head[x]=cnt; } void dfs(int x,int fa){ Fa[x]=fa; for(int i=head[x];i;i=e[i].nxt){ int v=e[i].to; if(v!=fa) dfs(v,x); } dfsx[++tot]=x; return; } int solve(int x){ int k,ans=0; for(int i=1;i<=n;i++) f[i]=1; for(int i=1;i<=n;i++){ int k=dfsx[i]; if(Fa[k]&&~f[Fa[k]]&&~f[k]){ if(f[k]+f[Fa[k]]>=x){ f[Fa[k]]=-1; ans++; } else f[Fa[k]]=max(f[Fa[k]],f[k]+1); } } return ans; } int main(){ scanf("%d",&n); q=sqrt(n*log(n)/log(2)); for(int i=1;i<n;i++){ scanf("%d %d",&x,&y); add(x,y); add(y,x); } dfs(1,0); printf("%d\n",n); for(int i=2;i<=q;i++) printf("%d\n",solve(i)); for(int i=q+1;i<=n;i=l+1){ l=i; r=n; t=solve(i); while(l<r){ mid=(l+r+1)>>1; if(solve(mid)==t) l=mid; else r=mid-1; } for(int j=i;j<=l;j++) printf("%d\n",t); } return 0; }
不要忘记点个赞哦
完结撒花
本文作者:AFewSuns
本文链接:https://www.cnblogs.com/AFewSuns/p/12623769.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步