题意:
给你一棵n个节点的树,每个点有一个权值,初始全为0,m次操作,每次三个数(v, d, x)表示只考虑以v为根的子树,将所有与v点距离小于等于d的点权值全部加上x,求所有操作完毕后,所有节点的值
思路:
O(n)DFS一遍即可,既然只用最后输出答案,果断离线,存下每个点的所有操作
设deep[x]为x点的深度
- 当第一次DFS到点v时,将深度在deep[v]到deep[v+d]的点权值全部加上x
- 当搜完点v所有的子孙准备回溯时,将深度在deep[v]到deep[v+d]的点权值全部减去x
- 这样每次搜到点v,当前深度的总权值就是答案
以上可以用BIT解决,当然也可以直接差分
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
typedef struct Res
{
LL val;
int dep;
}Res;
Res s[300005];
vector<int> G[300505];
vector<Res> F[300505];
int n;
LL ans[300505], out[300505];
void Sech(int u, int p, int deep, LL val)
{
Res now;
int i, v;
for(i=0;i<F[u].size();i++)
{
now = F[u][i];
out[deep] += now.val, out[min(deep+now.dep+1, n+5)] -= now.val;
}
val += out[deep];
//printf("%d %d %lld %lld\n", u, deep, out[deep], val);
ans[u] = val;
for(i=0;i<G[u].size();i++)
{
v = G[u][i];
if(v==p)
continue;
Sech(v, u, deep+1, val);
}
for(i=0;i<F[u].size();i++)
{
now = F[u][i];
out[deep] -= now.val, out[min(deep+now.dep+1, n+5)] += now.val;
}
}
int main(void)
{
Res now;
int m, i, x, y;
scanf("%d", &n);
for(i=1;i<=n-1;i++)
{
scanf("%d%d", &x, &y);
G[x].push_back(y);
G[y].push_back(x);
}
scanf("%d", &m);
for(i=1;i<=m;i++)
{
scanf("%d%d%lld", &x, &y, &now.val);
now.dep = y;
F[x].push_back(now);
}
Sech(1, 0, 1, 0ll);
for(i=1;i<=n;i++)
printf("%lld ", ans[i]);
puts("");
return 0;
}