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;
}

 

posted @ 2022-03-10 10:00  我微笑不代表我快乐  阅读(72)  评论(0编辑  收藏  举报