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 }
原文地址:https://www.cnblogs.com/computer-luo/p/9970985.html