链接:http://codeforces.com/problemset/problem/1076/E
题意:给你一颗以1为根节点的树,初始所有节点的权值为0,然后有m个操作,每个操作将点v的儿子节点中和本身的所有距离不超过d的节点权值加x,问经过m次操作后,输出每个节点的权值。
题解:如果是一个序列,就可以直接用树状数组做,但这是一颗树,所以我们可以想办法把它转化成序列。我们可以先求出每个节点的dfs序,以及深度和子树的大小,顺便记录每个深度都有哪些节点,子树的大小用来确认以该节点为根的子树在dfs序中的范围,此时便可用树状数组维护了。之后,我们把每个操作按能影响到的深度从大到小排序,即优先处理影响深度大的操作。设当前计算的深度为now,假设所有操的作影响的深度大于now的操作已经计算。如果当前操作影响的深度小于now,说明所有能影响到now深度的操作已经全部操作完了,此时把所有深度为now的节点权值计算出来。每读取一个操作的信息,就把操作产生的影响用树状数组维护,因为影响now深度的节点权值已经计算完毕了,所以我把以该操作的操作节点为根的子树全部加上操作的值 对之前已经计算的答案没有影响。操作全部完成后,深度从深到浅计算答案即可。
代码:
#include <bits/stdc++.h> #define IO_read ios::sync_with_stdio(false);cin.tie(0) #define fre freopen("in.txt", "r", stdin) #define _for(i,a,b) for(int i=a; i< b; i++) #define _rep(i,a,b) for(int i=a; i<=b; i++) using namespace std; typedef long long ll; #define lowbit(a) ((a)&-(a)) const int maxn=3e5+5; int tot, head[maxn*2]; struct Edge{ int to, next; }edge[maxn*2]; void addedge(int u, int v) { edge[++tot].to=v; edge[tot].next=head[u]; head[u]=tot; } int n, m; int deep[maxn], dfsn[maxn], sz[maxn]; int max_deep, cnt_dfs; vector<int> vec[maxn]; void dfs(int u, int now_deep) { max_deep=max(max_deep, now_deep); sz[u]=1, deep[u]=now_deep, dfsn[u]=++cnt_dfs; vec[now_deep].push_back(u); for(int i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].to; if(dfsn[v]) continue; //连了2次边,要判断 dfs(v, now_deep+1); sz[u]=sz[u]+sz[v]; } } struct Opt{ int rt, d, x; bool operator <(const Opt &a)const{ return deep[rt]+d>deep[a.rt]+a.d; } }opt[maxn]; ll tree[maxn], ans[maxn]; void add(int x, int val) { for(int i=x; i<=n; i+=lowbit(i)) tree[i]+=val; } ll ask(int x) { ll res=0; for(int i=x; i; i-=lowbit(i)) res+=tree[i]; return res; } int main() { IO_read; //fre; memset(head, -1, sizeof(head)); cin>>n; _rep(i, 1, n-1) { int u, v; cin>>u>>v; addedge(u, v); addedge(v, u); } cin>>m; _rep(i, 1, m) cin>>opt[i].rt>>opt[i].d>>opt[i].x; dfs(1, 1); //注意后面的排序用到了deep数组,所以要先dfs,在排序 sort(opt+1, opt+1+m); int now_deep=max_deep; _rep(i, 1, m) { int rt=opt[i].rt, d=opt[i].d, x=opt[i].x; while(deep[rt]+d<now_deep) { for(int j=0; j<vec[now_deep].size(); j++) { int v=vec[now_deep][j]; ans[v]=ask(dfsn[v]); } now_deep--; } add(dfsn[rt], x); add(dfsn[rt]+sz[rt], -x); } while(now_deep) //注意这样写deep从1开始 { for(int j=0; j<vec[now_deep].size(); j++) { int v=vec[now_deep][j]; ans[v]=ask(dfsn[v]); } now_deep--; } _rep(i, 1, n) cout<<ans[i]<<" "; return 0; }