DFS序2
给一棵有根树,这棵树由编号为1..N的N个结点组成。
根结点的编号为R 。每个结点都有一个权值,结点i的权值为Vi。
接下来有M组操作,操作分为两类:
1 a x,表示将结点a的子树上所有结点的权值增加x
2 a,表示求结点a的子树上所有结点的权值之和。
输入格式
第一行有三个整数N,M和 R。
第二行有N个整数,第i个整数表示Vi 。
在接下来的N-1行中,每行两个整数,表示一条边。
在接下来的M行中,每行一组操作。
1<=N,M<=1e6
-1e6<=vi,x<=1e6
输出格式
对于每组2 a操作,输出一个整数,表示「以结点a为根的子树」上所有结点的权值之和。
样例
输入
10 14 9
12 -6 -4 -3 12 8 9 6 6 2
8 2
2 10
8 6
2 7
7 1
6 3
10 9
2 4
10 5
1 4 -1
2 2
1 7 -1
2 10
1 10 5
2 1
1 7 -5
2 5
1 1 8
2 7
1 8 8
2 2
1 5 5
2 6
输出
21
33
16
17
27
76
30
#include <cstdio> const int maxn = 1000005; typedef long long LL; int n, m, r; int t[maxn], b[maxn]; // 线段树 LL tree[maxn << 2], mark[maxn << 2]; void build(int p, int l, int r){ if(l == r){ tree[p] = b[l]; return; } int mid = (l + r) / 2; build(2 * p, l , mid); build(2 * p + 1, mid + 1, r); tree[p] = tree[2 * p] + tree[2 * p + 1]; } void push_down(int p, int len){ tree[2 * p] += (len - len / 2) * mark[p]; tree[2 * p + 1] += (len / 2) * mark[p]; mark[2 * p] += mark[p]; mark[2 * p + 1] += mark[p]; mark[p] = 0; } void add(int p, LL x, int cl, int cr, int l, int r){ if(cr < l || cl > r) return; if(l <= cl && cr <= r){ tree[p] += x * (cr - cl + 1); mark[p] += x; } else { push_down(p, cr - cl + 1); int mid = (cl + cr) / 2; add(2 * p, x, cl, mid, l , r); add(2 * p + 1, x, mid + 1, cr, l, r); tree[p] = tree[2 * p] + tree[2 * p + 1]; } } LL query(int p, int cl, int cr, int l, int r){ if(cr < l || cl > r) return 0; if(l <= cl && cr <= r) return tree[p]; push_down(p, cr - cl + 1); int mid = (cl + cr) / 2; return query(2 * p, cl, mid, l, r) + query(2*p + 1, mid + 1, cr, l, r); } // 链式前向星 struct Edge{ int to, next; } edge[maxn << 1]; int cnt = 0; int head[maxn]; void add_edge(int u, int v){ edge[++cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt; } // dfs序 int tim = 0, L[maxn], R[maxn]; void dfs(int p, int fa) { L[p] = ++tim; b[tim] = t[p]; for(int e = head[p]; e; e = edge[e].next) { int &to = edge[e].to; if(to != fa) dfs(to, p); } R[p] = tim; } int main(){ scanf("%d%d%d", &n, &m, &r); for(int i=1; i <= n; i++){ scanf("%d", &t[i]); } for(int i=1, u, v; i < n; i++){ scanf("%d%d", &u, &v); add_edge(u, v); add_edge(v, u); } dfs(r, 0); build(1, 1, n); for(int i=1, op, a, x; i <= m; i++){ scanf("%d", &op); if(op == 1){ scanf("%d%d", &a, &x); add(1, x, 1, n, L[a], R[a]); } else { scanf("%d", &a); printf("%lld\n", query(1, 1, n, L[a], R[a])); } } return 0; }