1. 程式人生 > >BZOJ_4034 [HAOI2015]樹上操作 【樹鏈剖分dfs序+線段樹】

BZOJ_4034 [HAOI2015]樹上操作 【樹鏈剖分dfs序+線段樹】

for d+ ems ans bit mil href 編號 lazy

一 題目

  [HAOI2015]樹上操作

二 分析

  樹鏈剖分的題,這裏主要用到了$dfs$序,這題比較簡單的就是不用求$lca$。

  1.和樹鏈剖分一樣,先用鄰接鏈表建雙向圖。

  2.跑兩遍$dfs$,其實這題可以不這麽寫,主要是為了確定樹型結構轉線型後各節點的編號,以及各個鏈的$top$,$top$很關鍵,沒有$top$就需要不斷找父節點。

  3.建線段樹,這裏一定一定一定要仔細,寫太醜就會調很久。o(╯□╰)o

  4.修改操作和常規線段樹沒有區別,但修改就需要對鏈上的$top$節點和父節點不斷更新,知道找到根節點就可以了。

三 AC代碼

  1 /**************************************************************
2 Problem: 4034 3 User: Dybala21 4 Language: C++ 5 Result: Accepted 6 Time:2752 ms 7 Memory:16844 kb 8 ****************************************************************/ 9 10 #include <bits/stdc++.h> 11 using namespace std; 12 #define ll long long 13
14 const int MAXN = 1e5 + 14; 15 int n, m; 16 int cost[MAXN]; 17 int e[MAXN][2]; 18 struct Edge 19 { 20 int to, next; 21 }edge[MAXN*2]; 22 int head[MAXN], tot; 23 int fa[MAXN]; 24 int p[MAXN]; 25 int deep[MAXN]; 26 int size[MAXN]; 27 int son[MAXN]; 28 int top[MAXN];
29 int pos; 30 void init() 31 { 32 tot = 0, pos = 0; 33 memset(head, -1, sizeof(head)); 34 memset(son, -1, sizeof(son)); 35 } 36 void addedge(int u, int v) 37 { 38 edge[tot].to = v; 39 edge[tot].next = head[u]; 40 head[u] = tot++; 41 } 42 void dfs(int u, int pre, int d) 43 { 44 fa[u] = pre; 45 deep[u] = d; 46 size[u] = 1; 47 for(int i = head[u]; i != -1; i = edge[i].next) 48 { 49 int v = edge[i].to; 50 if(v != pre) 51 { 52 dfs(v, u, d+1); 53 size[u] += size[v]; 54 if(son[u] == -1 || size[v] > size[son[u]]) 55 son[u] = v; 56 } 57 } 58 } 59 void dfs2(int u, int sp) 60 { 61 top[u] = sp; 62 63 if(son[u] != -1) 64 { 65 p[u] = ++pos; 66 dfs2(son[u], sp); 67 } 68 else 69 { 70 p[u] = ++pos; 71 return; 72 } 73 74 for(int i = head[u]; i != -1; i = edge[i].next) 75 { 76 int v = edge[i].to; 77 if(v != son[u] && v != fa[u]) 78 dfs2(v, v); 79 } 80 } 81 struct Node 82 { 83 int l, r; 84 ll sum, lazy;; 85 }segTree[MAXN*3]; 86 void build(int rt, int l, int r) 87 { 88 segTree[rt].l = l; 89 segTree[rt].r = r; 90 segTree[rt].lazy = 0; 91 segTree[rt].sum = 0; 92 if(l == r) 93 return; 94 int mid = (l + r) >> 1; 95 build(rt<<1, l, mid); 96 build(rt<<1|1, mid + 1, r); 97 } 98 void pushdown(int rt) 99 { 100 if(segTree[rt].l == segTree[rt].r) 101 return; 102 int mid = (segTree[rt].l + segTree[rt].r)>>1; 103 ll t = segTree[rt].lazy; 104 segTree[rt].lazy = 0; 105 segTree[rt<<1].lazy += t; 106 segTree[rt<<1|1].lazy += t; 107 segTree[rt<<1].sum += t*(mid-segTree[rt].l+1); 108 segTree[rt<<1|1].sum += t*(segTree[rt].r-mid); 109 } 110 void update(int rt, int l, int r, ll val) 111 { 112 if(segTree[rt].lazy != 0) 113 pushdown(rt); 114 if(segTree[rt].l == l && segTree[rt].r == r) 115 { 116 segTree[rt].sum += (r-l+1)*val; 117 segTree[rt].lazy += val; 118 return; 119 } 120 int mid = (segTree[rt].l + segTree[rt].r)>>1; 121 if(r <= mid) 122 update(rt<<1, l, r, val); 123 else if(l > mid) 124 update(rt<<1|1, l, r, val); 125 else 126 { 127 update(rt<<1, l, mid, val); 128 update(rt<<1|1, mid + 1, r, val); 129 } 130 segTree[rt].sum = segTree[rt<<1].sum + segTree[rt<<1|1].sum; 131 } 132 ll query(int rt, int l, int r) 133 { 134 if(segTree[rt].lazy) 135 pushdown(rt); 136 if(segTree[rt].l == l && segTree[rt].r == r) 137 return segTree[rt].sum; 138 int mid = (segTree[rt].l + segTree[rt].r)>>1; 139 if(r <= mid) 140 return query(rt<<1, l, r); 141 else if(l > mid) 142 return query(rt<<1|1, l, r); 143 else 144 { 145 ll res = 0; 146 res += query(rt<<1, l, mid); 147 res += query(rt<<1|1, mid+1, r); 148 return res; 149 } 150 } 151 ll query(int x) 152 { 153 ll ans = 0; 154 while(top[x] != 1) 155 { 156 ans += query(1, p[top[x]], p[x]); 157 x = fa[top[x]]; 158 } 159 ans += query(1, 1, p[x]); 160 return ans; 161 } 162 int main() 163 { 164 //freopen("in.txt", "r", stdin); 165 //freopen("out.txt", "w", stdout); 166 init(); 167 scanf("%d%d", &n, &m); 168 for(int i = 1; i <= n; i++) 169 { 170 scanf("%d", &cost[i]); 171 } 172 for(int i = 0; i < n-1; i++) 173 { 174 scanf("%d%d", &e[i][0], &e[i][1]); 175 addedge(e[i][0], e[i][1]); 176 addedge(e[i][1], e[i][0]); 177 } 178 dfs(1, 0, 0); 179 dfs2(1, 1); 180 build(1, 1, pos); 181 for(int i = 1; i <= n; i++) 182 update(1, p[i], p[i], cost[i]); 183 int op, x, xa; 184 for(int i = 0; i < m; i++) 185 { 186 scanf("%d", &op); 187 if(op == 1) 188 { 189 scanf("%d%d", &x, &xa); 190 update(1, p[x], p[x], xa); 191 } 192 else if(op == 2) 193 { 194 scanf("%d%d", &x, &xa); 195 update(1, p[x], p[x] + size[x] - 1, xa); 196 } 197 else 198 { 199 scanf("%d", &x); 200 printf("%lld\n", query(x) ); 201 } 202 } 203 return 0; 204 } 205

BZOJ_4034 [HAOI2015]樹上操作 【樹鏈剖分dfs序+線段樹】