Codeforces Round#225 div.2E Propagating tree 线段树

题意:

给你一颗树,现在有两个操作:

1 x val:代表着对节点x进行加val,那么他的孩子节点-val,他的孙子节点+val,依次类推

2 x:代表着你要打印这个节点的值。

思路:

线段树区间更新,单点查询。对于每一个节点,都会有一个对应的控制区间,我们首先DFS一把,找到每个点的控制区间,并且DFS的时候顺便把每一个节点处于什么层次顺便一起记下来。对于该题,我们建立两颗线段树,一颗为奇树,一颗为偶树。对于处于奇数层的节点,我们让它的奇树加,偶树减,同理,处于偶数层的节点,我们让它的偶树加,奇树减,相互不会干扰,并且恰好该节点的应有操作是正确的。

代码:

/*
Algorithm&&Data Structure:Segment Tree && DFS
Source:Codeforces 383C Propagating tree
*/
#define _CRT_SECURE_NO_WARNINGS
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<iostream>
#include<stdlib.h>
#include<set>
#include<vector>
using namespace std;
#define maxn 200010
#define Lchild rt<<1,L,m
#define Rchild rt<<1|1,m+1,R
#define LL long long

int  arr[maxn];
int tree[2][maxn << 2];
LL lazy[2][maxn << 2];
int N,M;
int u, v;

struct node
{
	int to,next;
	node()
	{
		to = 0;
		next = -1;
	}
};
node Edge[maxn << 2];
int count_edge;
int head[maxn];
int dep[maxn], count_dep = 0;
int in[maxn], ou[maxn];
int count_num = 0;
int x, val;
void addedge(int u, int v)
{
	Edge[count_edge].to = v;
	Edge[count_edge].next = head[u];
	head[u] = count_edge;
	count_edge++;
}
void dfs(int no,int front)
{
	dep[no] = dep[front] + 1;
	in[no] = ++count_num;
	for (int k = head[no]; k!=-1; k = Edge[k].next)
	{
		/*if (Edge[k].to == front)
			continue;*/
		dfs(Edge[k].to,no);
	}
	ou[no] = count_num;
}
void pushDown(int rt, int o, int len)
{
	tree[o][rt << 1] += lazy[o][rt] * (len - (len >> 1));
	lazy[o][rt << 1] += lazy[o][rt];
	tree[o][rt << 1 | 1] += lazy[o][rt] * (len >> 1);
	lazy[o][rt << 1 | 1] += lazy[o][rt];
	lazy[o][rt] = 0;
}
void update(int val, int l, int r, int o, int rt = 1, int L = 1, int R = N)
{
	if (l <= L&&R <= r)
	{
		tree[o][rt] += val;
		lazy[o][rt] += val;
		return;
	}
	if (lazy[o][rt])
		pushDown(rt, o, R - L + 1);
	int m = (R + L) >> 1;
	if (l <= m)
		update(val, l, r, o, Lchild);
	if (r>m)
		update(val, l, r, o, Rchild);
}
int query(int pos,int o,int rt=1,int L=1,int R=N)
{
	if (L == R)
	{
		return tree[o][rt];
	}
	if (lazy[o][rt])
		pushDown(rt, o, R - L + 1);
	int m = (L + R) >> 1;
	if (pos <= m)
		return query(pos, o, Lchild);
	else
		return query(pos, o, Rchild);
}
void input()
{
	cin >> N >> M;
	count_edge = 0;
	for (int i = 1; i <= N; i++)
	{
		scanf("%d", &arr[i]);
	}
	for (int i = 0; i <= N; i++)
		head[i] = -1;
	for (int i = 1; i < N; i++)
	{
		scanf("%d%d", &u, &v);
		addedge(u, v);
		//addedge(v, u);
	}
	dep[0] = 0;
	dfs(1, 0);
	int num;
	for (int i = 0; i < M; i++)
	{
		scanf("%d", &num);
		if (num == 1)
		{
			scanf("%d%d", &x, &val);
			update(val, in[x], ou[x], dep[x] & 1);
			update(-val, in[x] + 1, ou[x], !(dep[x] & 1));
		}
		else
		{
			scanf("%d", &x);
			cout << query(in[x], dep[x] & 1) + arr[x] << endl;
		}
	}
}
int main()
{
	input();
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值