[BZOJ4034] [HAOI2015] T2 (树链剖分)
Description
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
Input
第一行包含两个整数 N, M 。表示点数和操作数。
接下来一行 N 个整数,表示树中节点的初始权值。
接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。
再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操
作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
Sample Input
5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
Sample Output
6
9
13
9
13
HINT
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。
Source
Solution
树链剖分,用线段树维护点权;对子树的修改就是区间修改,因为其dfs序是连续的
1 #include <bits/stdc++.h> 2 using namespace std; 3 struct edge 4 { 5 int v, nxt; 6 }e[200005]; 7 struct point 8 { 9 int val, siz, fa, son, dfn, top; 10 }p[100005]; 11 struct seg 12 { 13 long long val, lazy; 14 }a[300005]; 15 int fst[100005], ptot; 16 17 void addedge(int i, int u, int v) 18 { 19 e[i] = (edge){v, fst[u]}, fst[u] = i; 20 } 21 22 void DFS1(int u) 23 { 24 p[u].siz = 1; 25 for(int i = fst[u]; i; i = e[i].nxt) 26 if(p[u].fa != e[i].v) 27 { 28 p[e[i].v].fa = u; 29 DFS1(e[i].v); 30 p[u].siz += p[e[i].v].siz; 31 if(p[e[i].v].siz > p[p[u].son].siz) 32 p[u].son = e[i].v; 33 } 34 } 35 36 void DFS2(int u, int top) 37 { 38 p[u].dfn = ++ptot, p[u].top = top; 39 if(p[u].son) DFS2(p[u].son, top); 40 for(int i = fst[u]; i; i = e[i].nxt) 41 if(e[i].v != p[u].fa && e[i].v != p[u].son) 42 DFS2(e[i].v, e[i].v); 43 } 44 45 void push_up(int o, int l, int r) 46 { 47 a[o].val = a[o << 1].val + a[o << 1 | 1].val; 48 a[o].val += a[o].lazy * (r - l + 1); 49 } 50 51 void push_down(int o, int l, int r) 52 { 53 int mid = (l + r) >> 1; 54 if(l == r) return; 55 if(a[o].lazy) 56 { 57 a[o << 1].lazy += a[o].lazy; 58 a[o << 1].val += a[o].lazy * (mid - l + 1); 59 a[o << 1 | 1].lazy += a[o].lazy; 60 a[o << 1 | 1].val += a[o].lazy * (r - mid); 61 a[o].lazy = 0; 62 } 63 } 64 65 void update(int o, int l, int r, int ql, int qr, int val) 66 { 67 int mid = (l + r) >> 1; 68 push_down(o, l, r); 69 if(ql <= l && r <= qr) 70 { 71 a[o].lazy += val; 72 a[o].val += (long long)val * (r - l + 1); 73 return; 74 } 75 if(ql <= mid) update(o << 1, l, mid, ql, qr, val); 76 if(mid < qr) update(o << 1 | 1, mid + 1, r, ql, qr, val); 77 push_up(o, l, r); 78 } 79 80 long long query(int o, int l, int r, int ql, int qr) 81 { 82 int mid = (l + r) >> 1; 83 long long ans = 0; 84 push_down(o, l, r); 85 if(ql <= l && r <= qr) return a[o].val; 86 if(ql <= mid) ans = query(o << 1, l, mid, ql, qr); 87 if(mid < qr) ans += query(o << 1 | 1, mid + 1, r, ql, qr); 88 return ans; 89 } 90 91 int main() 92 { 93 int n, m, u, v, op, x, val; 94 long long ans; 95 scanf("%d%d", &n, &m); 96 for(int i = 1; i <= n; ++i) 97 scanf("%d", &p[i].val); 98 for(int i = 1; i < n; ++i) 99 { 100 scanf("%d%d", &u, &v); 101 addedge(i << 1, u, v); 102 addedge(i << 1 | 1, v, u); 103 } 104 DFS1(1), DFS2(1, 1); 105 for(int i = 1; i <= n; ++i) 106 update(1, 1, n, p[i].dfn, p[i].dfn, p[i].val); 107 while(m--) 108 { 109 scanf("%d", &op); 110 if(op == 1) 111 { 112 scanf("%d%d", &x, &val); 113 update(1, 1, n, p[x].dfn, p[x].dfn, val); 114 } 115 else if(op == 2) 116 { 117 scanf("%d%d", &x, &val); 118 update(1, 1, n, p[x].dfn, p[x].dfn + p[x].siz - 1, val); 119 } 120 else 121 { 122 scanf("%d", &x); 123 ans = 0; 124 while(x) 125 { 126 ans += query(1, 1, n, p[p[x].top].dfn, p[x].dfn); 127 x = p[p[x].top].fa; 128 } 129 printf("%lld\n", ans); 130 } 131 } 132 return 0; 133 }