ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

树精题解(dfs序+二分查找+差分)_from_517coding

2020-10-24 21:31:38  阅读:182  来源: 互联网

标签:dep 题解 ll back dfs 树精 517coding add push


题面

        有一棵苹果树,经过一番艰苦卓绝的修炼,她成了精,为了给树上的苹果更好的滋养,她吸收来自于大地母亲的精华
  由于苹果树成精之后,技能大涨,她有特殊的滋养方式.
  具体说来,假设树上的每个分叉点都要一个苹果,一开始每个苹果的营养值都为0,接下来的m天,
  树精每天都会运用她吸收到的营养给苹果们增加营养,她每天会给某个子树内深度为d的苹果都增加一个营养值v,
  树的根节点的标号为1.现在树精想要知道,经过m天m次滋养之后,每个苹果的营养值分别是多少.

分析

  自然地想到用差分的方法来成段修改
  但是如何找出所有子树内与之相距为d的所有点,并且方便的存储维护呢?
  我们按照每层的dfs序的顺序将节点加入到对应的动态数组中,L[i]为点i第一次的dfs序,R[i]为点i第二次的dfs序列
  显然有如下性质
        1. 子树节点的dfs序介于 L[fa] 和 R[fa] ,反之也成立
        2. 同一层的dfs序列从左到右边递增
  故,我们可以利用二分法,找到第dep u + b 层的dfs序列中,第一个大于L[u]的序号 p,第一个大于R[u]的序号 q
  然后利用差分 c[dep u + b][p] += add,c[dep u + b][q] -= add,对c数组求一个前缀和就可以求出单点的最终权值了

代码实现

  坑点:有可能要修改的点不存在,要开long long 
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5 + 5;
ll a[N],n,m;
ll sum[N],dep[N],repl[N],L[N],R[N];//repl[]  dfs序对应的点号
vector<ll> e[N];// 图
vector<ll> x[N];// 每层的dfs序列
vector<ll> c[N];// 每层的差分数组,要和dfs序列同长度,初始值为0
ll dfscnt,md;
void dfs(ll u,ll fa)
{
	dep[u] = dep[fa] + 1;
	md = max(md,dep[u]);
	
	L[u] = ++dfscnt;
	repl[dfscnt] = u;
	x[dep[u]].push_back(L[u]);
	c[dep[u]].push_back(0);//保证同长度,和dfs序列一一对应
	
	for (auto v : e[u])
	{
		if(v != fa)
			dfs(v,u);
	}
	
	R[u] = ++dfscnt;
	repl[dfscnt] = u;
	x[dep[u]].push_back(R[u]);
	c[dep[u]].push_back(0);
}
// 同层内的dfs序从左到右是单调递增的
// 儿子的dfs序介于父亲的两个dfs序之间
ll ans[N];
int  main() 
{
	// freopen("c.in","r",stdin);
	// freopen("c.out","w",stdout);
	cin>>n>>m;
	for (ll i = 1,x,y; i < n; i++)
	{
		scanf("%lld%lld",&x,&y);
		e[x].push_back(y);
		e[y].push_back(x);
	}
	dfs(1,0);
	for (ll  i= 1,a,b,add; i <= m; i++)
	{
		scanf("%lld%lld%lld",&a,&b,&add);
		ll d = dep[a] + b;
		if(dep[a] + b > md)
			continue;//深度太大不存在
		ll l = upper_bound(x[d].begin(),x[d].end(),L[a]) - x[d].begin();
		ll r = upper_bound(x[d].begin(),x[d].end(),R[a]) - x[d].begin();
		
		c[d][l] += add;
                //如果恰好要修改到最右边会越界
		if(upper_bound(x[d].begin(),x[d].end(),R[a]) != x[d].end())
			c[d][r] -= add;
		
	}
	for(ll i = 1; i <= md; i++)
	{
		ll sum = 0;
		for(ll j = 0; j < c[i].size(); j++)
			sum+=c[i][j],ans[repl[x[i][j]]] = sum;//还原
	}
	for(ll i = 1;i <= n; i++)
	{
		printf("%lld ",ans[i]);
	}
	return 0;
}

标签:dep,题解,ll,back,dfs,树精,517coding,add,push
来源: https://www.cnblogs.com/awsl-712-717/p/13871158.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有