Codeforces Round #225 (Div. 1)-C. Propagating tree(线段树)

原题链接

C. Propagating tree
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Iahub likes trees very much. Recently he discovered an interesting tree named propagating tree. The tree consists of n nodes numbered from 1 to n, each node i having an initial value ai. The root of the tree is node 1.

This tree has a special property: when a value val is added to a value of node i, the value -val is added to values of all the children of node i. Note that when you add value -val to a child of node i, you also add -(-val) to all children of the child of node i and so on. Look an example explanation to understand better how it works.

This tree supports two types of queries:

  • "1 x val" — val is added to the value of node x;
  • "2 x" — print the current value of node x.

In order to help Iahub understand the tree better, you must answer m queries of the preceding type.

Input

The first line contains two integers n and m (1 ≤ n, m ≤ 200000). The second line contains n integers a1a2, ..., an (1 ≤ ai ≤ 1000). Each of the next n–1 lines contains two integers vi and ui (1 ≤ vi, ui ≤ n), meaning that there is an edge between nodes vi and ui.

Each of the next m lines contains a query in the format described above. It is guaranteed that the following constraints hold for all queries: 1 ≤ x ≤ n, 1 ≤ val ≤ 1000.

Output

For each query of type two (print the value of node x) you must print the answer to the query on a separate line. The queries must be answered in the order given in the input.

Examples
input
5 5
1 2 1 1 2
1 2
1 3
2 4
2 5
1 2 3
1 1 2
2 1
2 2
2 4
output
3
3
0
先算出深度为奇数的点有odd个,然后深搜,按顺序把深度为奇数的点放在vis[1..odd][内,把深度为偶数的点放在vis[odd+1..n]内
对于每个节点i, node[i].l1, node[i].r1表示以i为根节点的树上深度为奇数的点在vis上的范围,node[i].l2, node[i[.r2表示以i为节点的树上深度为偶数的点在vis上的范围
按照vis上点的顺序建立线段树,每次只要更新[node[i].l1, node[i].r1], [node[i].l2, node[i].r2]就行了
#include <bits/stdc++.h>
#define MOD 1000000007
#define maxn 200005
#define INF 1e18
using namespace std;
typedef long long ll;

struct Node{
	int l1, r1, l2, r2;
	int s1, s2, h;
}node[maxn];
int num[maxn<<2], add[maxn<<2], vis[maxn], value[maxn], p[maxn];
vector<int> v[maxn];
int e1, e2, odd, even;
void dfs1(int j, int f, int h){
	if(h&1)
	 odd++;
	else
	 even++;
	for(int i = 0; i < v[j].size(); i++){
		int k = v[j][i];
		if(k != f)
		 dfs1(k, j, h+1);
	}
}
void dfs2(int j, int f, int h){
	if(h&1){
		vis[++e1] = j;
		p[j] = e1; 
		node[j].s1 = 1;
	}
	else{
		vis[++e2] = j;
		p[j] = e2;
		node[j].s2 = 1;
	}

	node[j].h = h;
	node[j].l1 = e1;
	node[j].l2 = e2;
	for(int i = 0; i < v[j].size(); i++){
		int k = v[j][i];
		if(k != f)
		 dfs2(k, j, h+1);
	}
	if(node[j].s1)
	 node[j].r1 = e1;
	else{
		if(e1 > node[j].l1){
			node[j].s1 = 1;
			node[j].r1 = e1;
			node[j].l1++;
		}
	}
	if(node[j].s2)
	  node[j].r2 = e2;
	else{
		if(e2 > node[j].l2){
			node[j].s2 = 1;
			node[j].r2 = e2;
			node[j].l2++;
		}
	}
}
void Build(int s, int l, int r){
	if(l == r){
		num[s] = value[vis[l]];
		return ;
	}
	int mid = (l + r) >> 1;
	Build(s<<1, l, mid);
	Build(s<<1|1, mid+1, r);
	num[s] = num[s<<1] + num[s<<1|1];
}
void pushdown(int s, int L, int R){
	int mid = (L + R) >> 1;
	num[s<<1] += add[s] * (mid - L + 1);
	num[s<<1|1] += add[s] * (R - mid);
	add[s<<1] += add[s];
	add[s<<1|1] += add[s];
	add[s] = 0;
}
void Update(int s, int l, int r, int L, int R, int h){
	if(l == L && R == r){
		add[s] += h;
		num[s] += (r - l + 1) * h;
		return ;
	}
	if(add[s])
	  pushdown(s, L, R);
	int mid = (L + R) >> 1;
	if(r <= mid)
	 Update(s<<1, l, r, L, mid, h);
	else if(l > mid)
	 Update(s<<1|1, l, r, mid+1, R, h);
	else{
		Update(s<<1, l, mid, L, mid, h);
		Update(s<<1|1, mid+1, r, mid+1, R, h);
	}
	num[s] = num[s<<1] + num[s<<1|1];
}
int Query(int s, int L, int R, int e){
	if(L == R){
		return num[s];
	}
	if(add[s])
	 pushdown(s, L, R);
	int mid = (L + R) >> 1;
	if(e <= mid)
	 return Query(s<<1, L, mid, e);
	return Query(s<<1|1, mid+1, R, e);
}
int main(){
//	freopen("in.txt", "r", stdin);
	int n, m, a, b, c;
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++)
	 scanf("%d", value+i);
	for(int i = 1; i < n; i++){
		scanf("%d%d", &a, &b);
		v[a].push_back(b);
		v[b].push_back(a);
	}
	dfs1(1, -1, 1);
	e1 = 0;
	e2 = odd;
	dfs2(1, -1, 1);
	Build(1, 1, n);
	while(m--){
		scanf("%d", &a);
		if(a == 1){
			scanf("%d%d", &b, &c);
			if(node[b].s1){
			 if(node[b].h % 2 == 0)
			  c = -c;
			 Update(1, node[b].l1, node[b].r1, 1, n, c);
		    }
		    c = abs(c);
			if(node[b].s2){
			 if(node[b].h&1)
			  c = -c;
			 Update(1, node[b].l2, node[b].r2, 1, n, c);
		   }
		}	
		else{
			scanf("%d", &b);
			printf("%d\n", Query(1, 1, n, p[b]));
		}
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值