bzoj 4034[HAOI2015]树上操作 - 树链剖分
4034: [HAOI2015]树上操作
Time Limit: 10 Sec Memory Limit: 256 MBDescription
有一棵点数为 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 。
一道树链剖分的练手题,以为一颗子树的DFS序是连续的,所以对子树的修改就相当于对一段区间的修改。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define LL long long 6 7 using namespace std; 8 9 int N, M; 10 LL ans = 0; 11 const int MAXN = 2e5 + 10; 12 int size[MAXN], son[MAXN], top[MAXN], fa[MAXN], dfn[MAXN], out[MAXN]; 13 LL val[MAXN]; 14 int m[MAXN]; 15 int head[MAXN], deep[MAXN]; 16 17 int cnt = 0; 18 struct segment { 19 LL val; 20 LL len; 21 LL lazy; 22 } seg[MAXN * 10]; 23 24 struct edge { 25 int v, next; 26 } g[MAXN * 2]; 27 28 inline LL read() 29 { 30 LL x = 0, w = 1; char ch = 0; 31 while(ch < '0' || ch > '9') { 32 if(ch == '-') { 33 w = -1; 34 } 35 ch = getchar(); 36 } 37 while(ch >= '0' && ch <= '9') { 38 x = x * 10 + ch - '0'; 39 ch = getchar(); 40 } 41 return x * w; 42 } 43 44 void pushdown(int root) 45 { 46 seg[root * 2].lazy += seg[root].lazy; 47 seg[root * 2 + 1].lazy += seg[root].lazy; 48 seg[root * 2].val += seg[root * 2].len * seg[root].lazy; 49 seg[root * 2 + 1].val += seg[root * 2 + 1].len * seg[root].lazy; 50 seg[root].lazy = 0; 51 } 52 53 void pushup(int root) 54 { 55 seg[root].val = seg[root * 2].val + seg[root * 2 + 1].val; 56 } 57 58 void build(int l, int r, int root) 59 { 60 seg[root].len = r - l + 1; 61 if(l == r) { 62 seg[root].val = val[m[l]]; 63 return; 64 } 65 int mid = (l + r) >> 1; 66 build(l, mid, root * 2); 67 build(mid + 1, r, root * 2 + 1); 68 pushup(root); 69 } 70 71 void dfs1(int x) 72 { 73 deep[x] = deep[fa[x]] + 1; 74 size[x] = 1; 75 for(int j = head[x]; j; j = g[j].next) { 76 int to = g[j].v; 77 if(fa[x] != to) { 78 fa[to] = x; 79 dfs1(to); 80 size[x] += size[to]; 81 if(size[son[x]] < size[to]) { 82 son[x] = to; 83 } 84 } 85 } 86 } 87 88 void dfs2(int x, int tp) 89 { 90 top[x] = tp; 91 dfn[x] = ++cnt; 92 m[cnt] = x; 93 if(son[x]) { 94 dfs2(son[x], tp); 95 } 96 for(int j = head[x]; j; j = g[j].next) { 97 int to = g[j].v; 98 if(!dfn[to]) { 99 dfs2(to, to); 100 } 101 } 102 out[x] = cnt; 103 } 104 105 void update(int ul, int ur, int l, int r, int root, LL k) 106 { 107 if(ul <= l && ur >= r) { 108 seg[root].val += seg[root].len * k; 109 seg[root].lazy += k; 110 return; 111 } 112 int mid = (l + r) >> 1; 113 pushdown(root); 114 if(mid >= ul) { 115 update(ul, ur, l, mid, root * 2, k); 116 } 117 if(ur > mid) { 118 update(ul, ur, mid + 1, r, root * 2 + 1, k); 119 } 120 pushup(root); 121 } 122 123 LL query(int ql, int qr, int l, int r, int root) 124 { 125 if(ql <= l && qr >= r) { 126 return seg[root].val; 127 } 128 pushdown(root); 129 LL sum = 0; 130 int mid = (l + r) >> 1; 131 if(mid >= ql) { 132 sum += query(ql, qr, l, mid, root * 2); 133 } 134 if(mid < qr) { 135 sum += query(ql, qr, mid + 1, r, root * 2 + 1); 136 } 137 return sum; 138 } 139 140 void addedge(int u, int v) 141 { 142 g[++cnt].v = v; 143 g[cnt].next = head[u]; 144 head[u] = cnt; 145 } 146 147 LL cal(int x) 148 { 149 LL sum = 0; 150 while(top[x] != 1) { 151 sum += query(dfn[top[x]], dfn[x], 1, N, 1); 152 x = fa[top[x]]; 153 } 154 sum += query(1, dfn[x], 1, N, 1); 155 return sum; 156 } 157 158 int main() 159 { 160 N = read(), M = read(); 161 for(int i = 1; i <= N; i++) { 162 val[i] = read(); 163 } 164 for(int i = 1; i < N; i++) { 165 int u = read(), v = read(); 166 addedge(u, v); 167 addedge(v, u); 168 } 169 cnt = 0; 170 dfs1(1); 171 dfs2(1, 1); 172 build(1, N, 1); 173 /* for(int i = 1; i <= N; i++) { 174 cout<<dfn[i]<<" "<<out[i]<<endl; 175 }*/ 176 for(int i = 1; i <= M; i++) { 177 int opr = read(); 178 if(opr == 1) { 179 LL x = read(), a = read(); 180 update(dfn[x], dfn[x], 1, N, 1, a); 181 } else if(opr == 2) { 182 LL x = read(), a = read(); 183 update(dfn[x], out[x], 1, N, 1, a); 184 } else { 185 int x = read(); 186 ans = cal(x); 187 printf("%lld\n", ans); 188 } 189 } 190 return 0; 191 }