P1612 [yLOI2018] 树上的链
因为自己太憨了,所以交了好几次都没过,谢谢审核大大!!!
思路
因为这是一棵树,所以每个节点只有一个父亲,那么选定一个结点,它到根节点的路径唯一。
所以第一个思路就是暴力,对于每一个节点,直接暴力向上枚举,找到第一个满足条件的节点,然后输出长度即可。
但是显然,第一种方法很容易 TLE,所以我们需要进一步优化。
我们随便给出一棵树,选取一条链。以叶节点为例,那么找到的最长链的另一个端点应该在路径上。
那么我们很容易想到了二分,快速找到适合的节点。
但是如果二分后还是暴力把所有值加在一起的话显然还是会超时,所以我们又自然地想到了前缀和。
最后一个问题,我们该如何确定二分的范围呢?我们可以在深搜的时候用一个栈,每搜索到一个新节点,就加入栈,然后在栈中二分,当这个节点遍历完了,就出栈。
对了,需要注意的是,这道题需要开 long long
。
AC 代码
#include<bits/stdc++.h> using namespace std; struct node{long long w,c,fa;vector<long long>v;}a[100005];//因为不确定儿子个数,所以用vector储存 long long n,ans[100005],z[100005],top,l,r,mid; void dfs(long long u) { z[++top]=u;//入栈 l=0,r=top; a[u].w+=a[a[u].fa].w;//前缀和 while(l<=r)//二分 { mid=l+r>>1; if(a[u].w-a[z[mid]].w>a[u].c) l=mid+1; else ans[u]=top-mid,r=mid-1; } for(long long i=0;i<a[u].v.size();i++) dfs(a[u].v[i]);//向下搜索 --top;//出栈 } int main() { scanf("%lld",&n); for(long long i=2;i<=n;++i) scanf("%lld",&a[i].fa),a[a[i].fa].v.push_back(i); for(long long i=1;i<=n;++i) scanf("%lld",&a[i].w); for(long long i=1;i<=n;++i) scanf("%lld",&a[i].c); dfs(1); for(long long i=1;i<=n;++i) printf("%lld ",ans[i]); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?