BZOJ 4034[HAOI2015]树上操作 树链剖分
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
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
题解:刷水有益健康...
#include <bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin), freopen(s".out","w",stdout) #define maxn 110000 #define ll long long #define lson (x<<1) #define rson ((x<<1)|1) using namespace std; int hd[maxn], to[maxn << 1], nex[maxn << 1], st[maxn], ed[maxn]; int fa[maxn], dep[maxn], dfn[maxn], ln[maxn], hson[maxn], siz[maxn], bot[maxn], top[maxn]; int edges, n , Q, tim; ll val[maxn]; void add(int u, int v) { nex[++edges] = hd[u], hd[u] = edges, to[edges] = v; } void dfs1(int u, int ff) { fa[u] = ff, dep[u] = dep[ff] + 1, siz[u] = 1; for(int i = hd[u]; i ; i = nex[i]) { int v = to[i]; if(v == ff) continue; dfs1(v, u); siz[u] += siz[v]; if(siz[v] > siz[hson[u]]) hson[u] = v; } } void dfs2(int u, int tp) { top[u] = tp, ln[++tim] = u, dfn[u] = tim, st[u] = tim; if(hson[u]) dfs2(hson[u], tp), bot[u] = bot[hson[u]]; else bot[u] = u; for(int i = hd[u]; i ; i = nex[i]) { int v = to[i]; if(v == fa[u] || v == hson[u]) continue; dfs2(v, v); } ed[u] = tim; } struct Node { ll lazy, val, sumv; }t[maxn << 3]; void mark(int l, int r, int x, ll d) { t[x].lazy += d; ll tmp = r - l + 1; t[x].sumv += 1ll*tmp*1ll*d; } void pushdown(int l, int r, int x) { if(!t[x].lazy) return; int mid = (l + r) >> 1; if(mid >= l) mark(l, mid, lson, t[x].lazy); if(r > mid) mark(mid + 1, r, rson, t[x].lazy); t[x].lazy = 0; } void build(int l, int r, int x) { if(l == r) { t[x].sumv = t[x].val = val[ln[l]]; return; } int mid = (l + r) >> 1; build(l, mid, lson); build(mid + 1, r, rson); t[x].sumv = t[lson].sumv + t[rson].sumv; } void update(int l, int r, int x, int L, int R, ll d) { pushdown(l, r, x); if(l >= L && r <= R) { mark(l, r, x, d); return; } int mid = (l + r) >> 1; if(L <= mid) update(l, mid, lson, L, R, d); if(R > mid) update(mid + 1, r, rson, L, R, d); t[x].sumv = t[lson].sumv + t[rson].sumv; } ll query(int l, int r, int x, int L, int R) { pushdown(l, r, x); if(l >= L && r <= R) return t[x].sumv; int mid = (l + r) >> 1; ll tmp = 0; if(L <= mid) tmp += query(l, mid, lson, L, R); if(R > mid) tmp += query(mid + 1, r, rson, L, R); return tmp; } void modify1(int x, ll d) { update(1, n, 1, dfn[x], dfn[x], d); } void modify2(int x, ll d) { update(1, n, 1, st[x], ed[x], d); } ll Query(int x) { ll tmp = 0; while(x) { tmp += query(1, n, 1, dfn[top[x]], dfn[x]); x = fa[top[x]]; } return tmp; } int main() { // setIO("input"); scanf("%d%d",&n,&Q); for(int i = 1;i <= n; ++i) scanf("%lld",&val[i]); for(int i = 1, u , v; i < n; ++i) { scanf("%d%d",&u,&v), add(u, v), add(v, u); } dfs1(1, 0), dfs2(1, 1), build(1, n, 1); while(Q--) { int opt, x; ll a; scanf("%d",&opt); if(opt == 1) { scanf("%d%lld",&x,&a), modify1(x, a); } if(opt == 2) { scanf("%d%lld",&x,&a), modify2(x, a); } if(opt == 3) { scanf("%d",&x); printf("%lld\n",Query(x)); } } return 0; }