牛客多校-Eezie and Pie-(倍增+树上差分)

B

题意:
给你一个树,根节点为1,然后每个点可以做蛋糕,但是只能送到从根节点到这个点的最简路径上的点,也就是1到当前点这条链上的点。但是每个点做的蛋糕有个保质期,如果送的长度>保质期就不行。现在问你每个点可以有多少点送蛋糕给自己。

思考:
1.很明显就是一个点的所有儿子到这个点的距离<=儿子的权值。由于是对每个点都输出答案,我就总感觉是树上启发式,但是好久没用了,有些淡忘,但是我看了看以前做过的启发式的题,感觉这题不能用启发式啊,因为每个点他所作的贡献并不是全局的,他做的贡献还要和祖宗节点比一下大小,如果保质期够大才行,但是启发式合并不行,因为你要保证每个点的贡献在不同的子树上是一样的才行。所以启发式就不行了,不过也要抽空好好复习一下。
2.但是这题过的也很快,我就感觉肯定不是启发式。我画了画图,对于每个点,他可以每次让这个点到上面某个点这条链上所有的点的答案都加1,因为他都可以送到。想到了区间加,我就想到了树上差分,后缀差分后求个后缀和就可以了。对于每个点他能送到的最祖先的点是谁的话,这里就可以像lca一样维护一个倍增,对于距离a点<=b的最远的点,可以每次倍增跳就行了。然后差分的时候注意!sum[acc[up][0]]-1,sum[down]+1。不是sum[up-1]+1。当时写的时候写顺手了,直接当数组用了。多多注意细节,仔细检查再提交。

代码:

#include<bits/stdc++.h>
#define int long long
#define pb push_back
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);

using namespace std;

const int N = 2e6+10;

int T,n,m;
int va[N];
int acc[N][25],dep[N],cnt=22;
int sum[N];

vector<int > e[N];

void dfs(int now,int p)
{
	acc[now][0] = p;
	dep[now] = dep[p]+1;
	for(auto spot:e[now])
	{
		if(spot==p) continue;
		dfs(spot,now);
	}
}

int query(int a,int b)
{
	int now = a,sum = b;
	for(int i=cnt;i>=0;i--)
	{
		if(sum>=(1ll<<i))
		{
			sum -= (1ll<<i);
			now = acc[now][i];
		}
	}
	return now;
}

void dfst(int now,int p)
{
	int up = query(now,va[now]);
	int down = now;
	up = acc[up][0];
	sum[up]--;
	sum[down]++;
	for(auto spot:e[now])
	{
		if(spot==p) continue;
		dfst(spot,now);
	}
}

void get(int now,int p)
{
	for(auto spot:e[now])
	{
		if(spot==p) continue;
		get(spot,now);
		sum[now] += sum[spot];
	}
}

signed main()
{
	scanf("%lld",&n);
	for(int i=1;i<n;i++)
	{
		int a,b;
		scanf("%lld%lld",&a,&b);
		e[a].pb(b);
		e[b].pb(a);
	}
	for(int i=1;i<=n;i++) cin>>va[i];
	dfs(1,0);
	for(int i=1;i<=cnt;i++)
	{
		for(int j=1;j<=n;j++)
		acc[j][i] = acc[acc[j][i-1]][i-1];
	}
	dfst(1,0);get(1,0);
	for(int i=1;i<=n;i++) printf("%lld ",sum[i]);
	return 0;
}

总结:
多多思考,仔细检查,认真仔细,别慌,不用急。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值