codeforces 1076E Vasya and a Tree 【dfs+树状数组】

题目:戳这里

题意:给定有n个点的一棵树,顶点1为根。m次操作,每次都把以v为根,深度dep以内的子树中所有的顶点(包括v本身)加x。求出最后每个点的值为多少。

解题思路:考虑到每次都只对点及其子树操作,要用dfs。设v当前要操作的点,操作的深度是dep,d[v]表示v的深度。要把深度[d[v],d[v]+dep]中所有点都加上x,暴力加是肯定不行的,于是想到要用树状数组或线段树。dfs+树状数组便是本题的基本思路。我们在搜索树的同时,维护以深度为下标的树状数组。为什么一个树形结构能够维护树状数组这样的线性结构呢?因为是对树的dfs,只要没有跳出点就一定搜一条线到底,这样搜索出来的点就能满足树状数组的线性。而每当跳出一个点,就把这个点给树状数组加的值减掉(回溯)即可。

附本人代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <queue>
 4 #include <vector>
 5 #define lowbit(x) x&-x
 6 typedef long long ll;
 7 const int maxn = 3e5+10;
 8 const ll inf = 1e18;
 9 using namespace std;
10 ll c[maxn];
11 vector<int> eg[maxn],dep[maxn];
12 vector<ll> op[maxn];
13 ll ans[maxn];
14 int n, m;
15 void add(int x, ll u) {
16     while(x <= n) {
17         c[x] += u;
18         x += lowbit(x);
19     }
20 }
21 ll sum(int x) {
22     ll res = 0;
23     while(x > 0) {
24         res += c[x];
25         x -= lowbit(x);
26     }
27     return res;
28 }
29 void dfs(int now, int pre, int d) {
30     for(int i = 0; i < op[now].size(); ++i) {
31         add(min(d + dep[now][i], n), op[now][i]);
32     }
33     ans[now] = sum(n) - sum(d-1);
34     for(auto i: eg[now]) {
35         if(i == pre) continue;
36         dfs(i, now, d+1);
37     }
38     for(int i = 0; i < op[now].size(); ++i) {
39         add(min(d + dep[now][i], n), -op[now][i]);
40     }
41 }
42 int main(){
43 
44     scanf("%d", &n);
45     int x, y;
46     for(int i = 1; i < n; ++i) {
47         scanf("%d %d", &x, &y);
48         eg[x].push_back(y);
49         eg[y].push_back(x);
50     }
51     scanf("%d", &m);
52     int v, d;
53     ll xi;
54     for(int i = 1; i <= m; ++i) {
55         scanf("%d %d %lld", &v, &d, &xi);
56         if(d > n) d = n;
57         dep[v].push_back(d);
58         op[v].push_back(xi);
59     }
60     dfs(1,0,1);
61     for(int i = 1; i <= n; ++i)
62     printf("%lld ", ans[i]);
63     return 0;
64 }
View Code

 

posted @ 2018-11-14 22:30  euzmin  阅读(409)  评论(0编辑  收藏  举报