[BZOJ4034][HAOI2015]樹上操作
阿新 • • 發佈:2017-10-15
str pro 答案 {} sample 第一個 date com out
Submit: 5752 Solved: 1850
[Submit][Status][Discuss]
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
9
13
4034: [HAOI2015]樹上操作
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 5752 Solved: 1850
[Submit][Status][Discuss]
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 51 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
69
13
HINT
對於 100% 的數據, N,M<=100000 ,且所有輸入數據的絕對值都不會超過 10^6 。
裸的樹剖
在劃分輕重鏈時處理dfs序
#include <cstdio> #include <algorithm> using namespace std; char buf[10000000], *ptr = buf - 1; inline int readint(){ int n = 0; bool flag = false; while(*++ptr < ‘0‘ || *ptr > ‘9‘) if(*ptr == ‘-‘) flag = true; while(*ptr >= ‘0‘ && *ptr <= ‘9‘) n = (n << 1) + (n << 3) + (*ptr++ & 15); return flag ? -n : n; } typedef long long ll; const intmaxn = 100000 + 10; int n, m; struct Edge{ int to, next; Edge(){} Edge(int _t, int _n): to(_t), next(_n){} }e[maxn * 2]; int fir[maxn] = {0}, cnt = 0; inline void ins(int u, int v){ e[++cnt] = Edge(v, fir[u]); fir[u] = cnt; e[++cnt] = Edge(u, fir[v]); fir[v] = cnt; } int fa[maxn], siz[maxn], son[maxn]; void dfs1(int u){ siz[u] = 1; son[u] = 0; for(int v, i = fir[u]; i; i = e[i].next){ v = e[i].to; if(v == fa[u]) continue; fa[v] = u; dfs1(v); siz[u] += siz[v]; if(!son[u] || siz[v] > siz[son[u]]) son[u] = v; } } int val[maxn], w[maxn], top[maxn], in[maxn], out[maxn], dfs_idx = 0; void dfs2(int u){ in[u] = ++dfs_idx; w[dfs_idx] = val[u]; if(!son[u]){ out[u] = dfs_idx; return; } top[son[u]] = top[u]; dfs2(son[u]); for(int v, i = fir[u]; i; i = e[i].next){ v = e[i].to; if(v == fa[u] || v == son[u]) continue; top[v] = v; dfs2(v); } out[u] = dfs_idx; } #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 ll sum[maxn * 4], tag[maxn * 4] = {0}; inline void pushup(int rt){ sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } void build(int l, int r, int rt){ if(l == r) sum[rt] = w[l]; else{ int mid = l + r >> 1; build(lson); build(rson); pushup(rt); } } inline void pushdown(int rt, int m){ if(tag[rt]){ sum[rt << 1] += tag[rt] * (m - (m >> 1)); sum[rt << 1 | 1] += tag[rt] * (m >> 1); tag[rt << 1] += tag[rt]; tag[rt << 1 | 1] += tag[rt]; tag[rt] = 0; } } int ql, qr, qv; inline void update(int l, int r, int rt){ if(ql <= l && r <= qr){ sum[rt] += (ll)qv * (r - l + 1); tag[rt] += qv; } else{ pushdown(rt, r - l + 1); int mid = l + r >> 1; if(ql <= mid) update(lson); if(qr > mid) update(rson); pushup(rt); } } inline ll query(int l, int r, int rt){ if(ql <= l && r <= qr) return sum[rt]; else{ pushdown(rt, r - l + 1); int mid = l + r >> 1; ll ret = 0; if(ql <= mid) ret += query(lson); if(qr > mid) ret += query(rson); return ret; } } inline void ask(){ int x = readint(); ll ans = 0; while(top[x] != 1){ ql = in[top[x]]; qr = in[x]; ans += query(1, n, 1); x = fa[top[x]]; } ql = in[1]; qr = in[x]; ans += query(1, n, 1); printf("%lld\n", ans); } int main(){ buf[fread(buf, sizeof(char), sizeof(buf), stdin)] = 0; n = readint(); m = readint(); for(int i = 1; i <= n; i++) val[i] = readint(); for(int i = 1; i < n; i++) ins(readint(), readint()); fa[1] = 0; dfs1(1); top[1] = 1; dfs2(1); build(1, n, 1); int opt, x; while(m--){ opt = readint(); if(opt == 1){ x = readint(); ql = qr = in[x]; qv = readint(); update(1, n, 1); } else if(opt == 2){ x = readint(); ql = in[x]; qr = out[x]; qv = readint(); update(1, n, 1); } else ask(); } return 0; }
[BZOJ4034][HAOI2015]樹上操作