CF1059E Split the Tree
LXIV.CF1059E Split the Tree
我们假设对于每个位置,已经求出了它可以往上延伸的长度,然后考虑DP。
设表示子树被分完后的最小边的数量。再设表示当这个数量最小时,点能够往上延伸的最长长度。
这运用了贪心的思想:因为少一条边,肯定是要比无论大多少都是要更优的。再大,也只对一条边有效,中一条边和中一条边,不都是一样的吗?
我们可以很轻松地得到转移方程:
如果在上面的转移方程中,得到了,那就意味着必须在位置开新边,令,加一。
现在主要的部分就是求出了。这个可以通过倍增法在时间里预处理出来。
则总复杂度为。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,L,S,val[100100],len[100100],anc[100100][20],sum[100100],dep[100100],f[100100],g[100100];
vector<int>v[100100];
void dfs1(int x){
for(int i=1;(1<<i)<=dep[x];i++)anc[x][i]=anc[anc[x][i-1]][i-1];
for(int i=19,y=x;i>=0;i--){
if(!anc[y][i])continue;
if(sum[x]-sum[anc[y][i]]+val[anc[y][i]]>S)continue;
if(dep[x]-dep[anc[y][i]]>=L)continue;
len[x]+=(1<<i),y=anc[y][i];
}
for(auto y:v[x])anc[y][0]=x,dep[y]=dep[x]+1,sum[y]=sum[x]+val[y],dfs1(y);
}
void dfs2(int x){
for(auto y:v[x])dfs2(y),f[x]=max(f[x],f[y]),g[x]+=g[y];
f[x]--;
if(f[x]==-1)f[x]=len[x],g[x]++;
}
signed main(){
scanf("%lld%lld%lld",&n,&L,&S);
for(int i=1;i<=n;i++){
scanf("%lld",&val[i]);
if(val[i]>S){puts("-1");return 0;}
}
for(int i=2,x;i<=n;i++)scanf("%lld",&x),v[x].push_back(i);
dep[1]=1,sum[1]=val[1],dfs1(1),dfs2(1);
// for(int i=1;i<=n;i++)printf("%lld ",len[i]);puts("");
printf("%lld\n",g[1]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?