1076E/Educational Codeforces Round 54-E. Vasya and a Tree<<dfs序 树状数组
题意
给定一棵树,初始每个节点权值为零,q次更改,每次修改将以v为顶点的深度为d的子树全部加上x,最后输出所有节点的权重。
思路
题目只要求每个点最后的值,那么经过观察,发现一个点最后的权值大小只与他的父节点的更新有关,那么我们就只需要考虑他的父节点到他这条链上的情况,把这条链拿出来成为线段,然后维护后缀和就能得到此点上的权值。每个节点的贡献为给$[h,h+d]$增加$x$,所以维护时,只要在$h+d$点上加上$x$即可。
但是问题考察的是一棵树,我们就需要动态来完成这条链,我们采用dfs序去扫描这棵树,当一个节点进入时,把他的贡献算上,退出时减去他的贡献,这样就能保证他不会影响别的链。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef pair<int,int> PII; 4 const int maxn=3e5+7; 5 vector<PII> query[maxn]; 6 vector<int> G[maxn]; 7 long long tree[maxn]; 8 long long ans[maxn]; 9 int depth[maxn],reflect[maxn]; 10 int st[maxn],ed[maxn]; 11 void dfs(int now,int far) 12 { 13 static int tot=0; 14 st[now]=++tot; 15 reflect[tot]=now; 16 if(far==-1) 17 { 18 depth[now]=1; 19 } 20 for(int i=0;i<G[now].size();i++) 21 { 22 int v=G[now][i]; 23 if(v==far) continue; 24 depth[v]=depth[now]+1; 25 dfs(v,now); 26 } 27 ed[now]=tot; 28 } 29 void add(int x,int v) 30 { 31 while(x<maxn) 32 { 33 tree[x]+=v; 34 x+=x&-x; 35 } 36 } 37 long long sum(int x) 38 { 39 long long ret=0; 40 while(x>0) 41 { 42 ret+=tree[x]; 43 x-=x&-x; 44 } 45 return ret; 46 } 47 int main() 48 { 49 int n; 50 memset(tree,0,sizeof(tree)); 51 scanf("%d",&n); 52 for(int i=1,u,v;i<=n-1;i++) 53 { 54 scanf("%d%d",&u,&v); 55 G[u].push_back(v); 56 G[v].push_back(u); 57 } 58 dfs(1,-1);//跑出dfs序 59 int q; 60 scanf("%d",&q); 61 while(q--)//存储所有询问,将他们按节点分开转换为dfs序的树上顺序 62 { 63 int v,d,x; 64 scanf("%d%d%d",&v,&d,&x); 65 d+=depth[v]; 66 d=min(d,n); 67 query[st[v]].push_back(make_pair(d,x)); 68 query[ed[v]+1].push_back(make_pair(d,-x));//在退出时清除贡献 69 } 70 for(int i=1;i<=n;i++) 71 { 72 for(int j=0;j<query[i].size();j++)//把这个节点上更新的都更新了 73 { 74 PII temp=query[i][j]; 75 add(temp.first,temp.second); 76 } 77 ans[reflect[i]]=sum(n)-sum(depth[reflect[i]]-1);//映射返回得到答案 78 } 79 for(int i=1;i<=n;i++) 80 { 81 printf("%lld ",ans[i]); 82 } 83 }