http://codeforces.com/contest/1076/problem/E
题意:
给你一棵n个点的树,以1为根。一开始n个点的权值为0,每个边的边长为1.
给你m个操作,每次给v,d,x。
把所有祖先是v的,且距离v不超过d的点的权值都加上x。
POINT:
就是一个树上的搜索,加上树状数组(x这个点的答案是他的深度到n这些权值的和)它要存,当前状态下,操作最深的深度要加的权值。
别忘记回溯就可以了。
搜到这个点的时候,把所有以这个点为根的操作载入树状数组。
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
#define LL long long
const int N = 3e5+55;
LL x[N];
vector<int>G[N];
int n;
void add(int pos,LL val)
{
if(pos>n) pos=n;
for(int i=pos;i<=n;i+=i&-i)
x[i]+=val;
}
LL query(int pos)
{
LL ans=0;
for(int i=pos;i>=1;i-=i&-i)
ans+=x[i];
return ans;
}
LL ans[N];
vector<int>F[N];
vector<int>V[N];
int vis[N];
void dfs(int u,int d)
{
vis[u]=1;
for(int i=0;i<F[u].size();i++){
add(d+F[u][i],V[u][i]);
}
ans[u]=query(n)-query(d-1);
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(vis[v]) continue;
dfs(v,d+1);
}
for(int i=0;i<F[u].size();i++){
add(d+F[u][i],-V[u][i]);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++){
int u,v;scanf("%d%d",&u,&v);
G[u].push_back(v);G[v].push_back(u);
}
int m;
scanf("%d",&m);
while(m--){
int v,d,x;
scanf("%d%d%d",&v,&d,&x);
F[v].push_back(d);
V[v].push_back(x);
}
dfs(1,1);
for(int i=1;i<=n;i++)
printf("%lld ",ans[i]);
}