1. 程式人生 > >bzoj 4034[HAOI2015]樹上操作 - 樹鏈剖分

bzoj 4034[HAOI2015]樹上操作 - 樹鏈剖分

絕對值 int lld += splay sed ring print esp

4034: [HAOI2015]樹上操作

Time Limit: 10 Sec Memory Limit: 256 MB

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

Sample Output

6
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 }
View Code

bzoj 4034[HAOI2015]樹上操作 - 樹鏈剖分