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;
}
posted @   One_JuRuo  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示