题意:
有一棵树,1是根节点,给出三个数x,d,v,表示以x为节点的子树中,深度小于等于d的每个节点值+v;
这题的难点在于,如何控制深度d;
先说我没做出来的思路:
1 如果我们直接以深度建立树状数组,在改变以2为根节点的子树的时候,同样深度为2的2,3会同时更改,但是3的并不在2的子树上;我们还要判断是否在一个子树上,就十分的复杂。
2 如果是直接用dfs序,就像上面所说,深度问题,假设2-3-4是一条路,2-5是另一条,2-6-7-8又是一条,深度<=1的都被改变,实现起来就很麻烦
AC思路:
不如从答案出发,分析每个点的更改的情况
根据题意我们得知,每个节点只有与他直线相连且深度比他小(不会形容)的节点才能改变他
我们可以直接用dfs一个点一个点的求值,dfs的特点想必大家都知道,他走过的节点符合我们上面说的情况,也就是说,他在路中走过的节点都可以更改当前节点(其余的任何节点都不会改变当前节点)
所以我们只需要走一步算一步(进行走的节点的改值操作)就可以了,
回溯时(更改路),也要对上一步操作撤回(增加的值减去,减去的值增加)。
这个跟第一个一样都是用深度解决问题,但是这个方法在dfs中就完全没有了第一种方法的顾虑,因为dfs搜索时走的节点一定是同一个子树的节点。
代码:
#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
#include<string.h>
#include<iostream>
#include<vector>
#define ll long long
ll val[300100],biao[300100],deep[300100];
ll n;
vector<vector<ll> >e(300100);
vector<pair<ll,ll> >h[300100];
ll lowbit(ll x)
{
return x&(-x);
}
void add(ll x,ll v)
{
for(ll j=x; j<=n; j+=lowbit(j))
val[j]+=v;
}
ll getsum(ll x)
{
ll ans=0;
for(ll j=x; j>0; j-=lowbit(j))
ans+=val[j];
return ans;
}
void DFS(ll x,ll step,ll fa)
{
for(ll i=0; i<h[x].size(); i++)
{
ll d=h[x][i].first;
ll v=h[x][i].second;
add(step,v);
add(step+d+1,-v);
}
deep[x]=getsum(step);
for(ll i=0; i<e[x].size(); i++)
{
ll cnt=e[x][i];
if(cnt==fa)continue;
if(biao[cnt]==0)
{
biao[cnt]=1;
DFS(cnt,step+1,x);
biao[cnt]=0;
}
}
for(ll i=0; i<h[x].size(); i++)
{
ll d=h[x][i].first;
ll v=h[x][i].second;
add(step,-v);
add(step+d+1,v);
}
}
int main()
{
ll m;
scanf("%lld",&n);
ll x,y,d,v;
for(ll i=1; i<n; i++)
{
scanf("%lld %lld",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
}
memset(val,0,sizeof(val));
scanf("%lld",&m);
for(ll i=0; i<m; i++)
{
scanf("%lld %lld %lld",&x,&d,&v);
h[x].push_back({d,v});
}
DFS(1,1,0);
for(ll i=1; i<=n; i++)
printf("%lld ",deep[i]);
printf("\n");
}