1. 程式人生 > >codeforces 1076E Vasya and a Tree 【dfs+樹狀陣列】

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