CF1059E Split the Tree

ans[u]:覆盖完u的子树需要的最少次数。
f[u]:花费最少次数覆盖完u的子树后,u还可以向上延伸的最大长度。
len[u]:从u开始可以向上延伸的最大长度。
正常情况下:
ans[u]+=ans[e[i].to]],f[u]=max(f[e[i].to])
若u为叶节点:
ans[u]=1,f[u]=len[u]
若到u时,f[e[i].to]刚好全部空了:
ans[u]+=ans[e[i].to],ans++,f[u]=len[u]
len[u]通过倍增可得,ans[u],f[u]树形dp即可。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int n,L,S,u;
int v[N],p[N][18],d[N],dis[N],len[N],f[N],ans[N];
int cnt,head[N];
struct edge{int next,to;}e[N<<1];

inline void add(int u,int v)
{
	cnt++;
	e[cnt].next=head[u];
	e[cnt].to=v;
	head[u]=cnt;
}
void dfs(int u)
{
	for (register int i=1; (1<<i)<=d[u]; ++i) p[u][i]=p[p[u][i-1]][i-1];
	for (register int i=head[u]; i; i=e[i].next)
	{
		d[e[i].to]=d[u]+1;
		dis[e[i].to]=dis[u]+v[e[i].to];
		p[e[i].to][0]=u;
		dfs(e[i].to);
	}	
}

void dfs2(int u)
{
	bool jay=false;
	for (register int i=head[u]; i; i=e[i].next)
	{
		jay=true;
		dfs2(e[i].to);
		ans[u]+=ans[e[i].to];
		f[u]=max(f[u],f[e[i].to]-1);
	}
	if (!jay)
	{
		f[u]=len[u];
		ans[u]=1;
		return;	
	}
	if (!f[u])
	{
		f[u]=len[u];
		ans[u]++;	
	}
}


signed main(){
	scanf("%lld%lld%lld",&n,&L,&S);
	for (register int i=1; i<=n; ++i) scanf("%lld",&v[i]);
	for (register int i=2; i<=n; ++i) scanf("%lld",&u),add(u,i);
	for (register int i=1; i<=n; ++i)
	if (v[i]>S)
	{
		puts("-1");
		return 0;		
	}
	d[1]=1; dis[1]=v[1]; dfs(1);
	for (register int i=1; i<=n; ++i)
	{
		u=i;
		for (register int j=20; j>=0; --j)
		if (p[u][j] && d[i]-d[p[p[u][j]][0]]<=L && dis[i]-dis[p[p[u][j]][0]]<=S) u=p[u][j];
		len[i]=d[i]-d[u]+1;
	//	printf("i=%lld len[i]=%lld\n",i,len[i]);
	}
	dfs2(1);
	printf("%lld\n",ans[1]);
return 0;	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值