CF 383C Propagating tree [想法+树状数组]

题意:

给一棵树

给出两种操作:

1.在某个结点上加上一个值,在这个结点所有的儿子结点上减去这个值,在这个结点的所有孙子结点上加上这个值,在所有曾孙子结点上减去这个值,直到底。

2.查询某个结点上的值

分析:

把这个问题转化为树状数组的区间求和

样例经过dfs处理后如下,每个结点处理出了两个值l,r,层数1,2,3...,层数为奇数的属性为0,层数为偶数的属性为1

可以看到,子树下的结点的两个数值都是包含在子数的根结点的两数范围内的

而子树根结点的兄弟结点的两数范围则不是包含在子树根结点的两数范围内的

可以看到只有子树下面的结点和子树的根结点有联系,而兄弟结点没有联系,这和题目给的条件也是一致的

考虑维护两个树状数组

每当对一个结点进行加操作的时候,如果这个结点属性为0,则在0号树状数组上操作,否则在1号数组上操作

操作如下

在数组的l号元素加上该值,在数组r号元素上减去这个值

当查看一个结点的值的时候

这个结点要加上的值是属性号树状数组前l项和,要减去的是非属性号树状数组的前l项和,然后加上原值,输出

为什么这样做?

因为同属性的号的影响是加,不同属性号的影响是减

因为前l项和不会包含兄弟结点的影响,比如,这里要得到3号结点的值,l[3]=8,前8项和中,已经把2号上的一正(2号元素)一负(7号元素)给抵消了。而加上了父亲结点的,祖宗结点的影响,因为,3号结点的l值,在父亲结点祖宗结点的两数范围之间

#include <iostream>
#include <vector>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define pb push_back
const int NN=222222;
int bit_2[2][NN*2+1];
int ALL_bit=NN*2;
int f[NN];
int clsfy[NN];
int sum_bit(int i,int bit[]){
	int s=0;while(i>0){s+=bit[i],i-= i & -i;}
	return s;
}
void add_bit(int i,int x,int bit[]){
	while(i<=ALL_bit){bit[i]+=x,i+= i & -i;}
}
vector<int> G[NN];
int m=1;
int l[NN],r[NN];
void dfs(int now,int fa,int k){
	l[now]=m++;
	clsfy[now]=k;
	for(int i=0;i<G[now].size();i++){
		int to=G[now][i];
		if(to==fa) continue;
		dfs(to,now,1-k);
	}
	r[now]=m++;
}
int main(){
#ifndef ONLINE_JUDGE
	freopen("/home/rainto96/in.txt","r",stdin);
#endif
	int n,m;cin>>n>>m;
	for(int i=1;i<=n;i++)	cin>>f[i];
	for(int i=1;i<=n-1;i++){
		int x,y;cin>>x>>y;
		G[x].pb(y);
		G[y].pb(x);
	}
	dfs(1,-1,0);
	while(m--){
		int kind;cin>>kind;
		if(kind==1){
			int pos,val;cin>>pos>>val;
			add_bit(l[pos],val,bit_2[clsfy[pos]]);
			add_bit(r[pos],-val,bit_2[clsfy[pos]]);
		}else{
			int pos;cin>>pos;
			cout<<f[pos]+sum_bit(l[pos],bit_2[clsfy[pos]])-sum_bit(l[pos],bit_2[1-clsfy[pos]])<<endl;
		}
	}
}
时间: 2024-08-22 18:36:48

CF 383C Propagating tree [想法+树状数组]的相关文章

Codeforces 383C . Propagating tree【树状数组,dfs】

题目大意: 有一棵树,对这个树有两种操作:1:表示为(1 x val),在编号为x的节点上加上val,然后给x节点的每个儿子加上- val,再给每个儿子的儿子加上-(- val),一直加到没有儿子为止.2:表示为(2 x)查询x节点上的值. 做法: 由于每次修改操作修改的并不是一个值,而是很多值,那我们将该题抽象成区间修改,点查询的问题.那怎么抽象呢?可以明白的是,每次操作虽然有加有减,但是每次做加法操作,或者减法操作的都是同一部分数(也就是说,在某次加上同一个数的节点们,下次操作一定是加上或者

poj 3321:Apple Tree(树状数组,提高题)

Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 18623   Accepted: 5629 Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been

HDU5293(SummerTrainingDay13-B Tree DP + 树状数组 + dfs序)

Tree chain problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1798    Accepted Submission(s): 585 Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,-,n.The

HDU 3333 Turing Tree(树状数组离线处理)

HDU 3333 Turing Tree 题目链接 题意:给定一个数组,每次询问一个区间,求出这个区间不同数字的和 思路:树状数组离线处理,把询问按右端点判序,然后用一个map记录下每个数字最右出现的位置,因为一个数字在最右边出现,左边那些数字等于没用了,利用树状数组进行单点修改区间查询即可 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <map> using n

codeforces 570 D. Tree Requests 树状数组+dfs搜索序

链接:http://codeforces.com/problemset/problem/570/D D. Tree Requests time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Roman planted a tree consisting of n vertices. Each vertex contains a low

POJ 3321 Apple Tree 【树状数组+建树】

题目链接:http://poj.org/problem?id=3321 Apple Tree Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 34812 Accepted: 10469 Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka like

poj 3321 Apple Tree(树状数组)

辉煌北大的月赛题质量真高啊,这种树状数组真难想到. 树状数组的基本用法是区间,单点的应用,起初这个怎么都想不到如何套用到树状数组. 转化方法是 将树上的节点信息查询,转为深度优先中节点顺序(代表结点编号).进结点与出结点分别代表该结点管辖范围. 题目大意级是说,给你一颗树,最初每个节点上都有一个苹果,有两种操作:修改(即修改某一个节点,修改时这一个节点苹果从有到无,或从无到有)和查询(查询某一个节点他的子树上有多少个苹果). 由于此题数据比较大(N<=10^5),而且不是标准的二叉树,所以这里我

HDU 3333 Turing Tree(树状数组 || 线段树)

题意:给定一个区间,q个查询,对于每次查询回答这个区间内所有不重复的数的和. 思路:可以考虑使用树状数组来做. 先读入所有查询,离线来做,将所有查询按右端点升序排序. 那么我们从给定区间的第一个元素开始遍历这个区间,在此过程中更新每一个元素上一次出现的位置,每次将现在位置加上a[i]并将lastpos位置减去a[i], 也就是说,我们每一步都是保留与当前位置距离最近的重复元素值,其余置零,那么这样肯定能保证答案正确, 如果遍历到的这个位置恰好是一个询问的右端点,那么我们输出修改后的区间值之和.

Binary Indexed Tree (树状数组)

树状数组是能够完成下述操作的数据结构 给一个初始值全为0的数列a1,a2,-an. *给定i,计算a1+a2+-+ai *给定i和x,执行ai += x 1.基于线段树的实现 如果使用线段树,只需要对RMQ的样例做少许修改就可以实现这两个功能.线段树的每个节点上维护的是对应的区间的和. 接下来,我们来看如何计算从s到t的和.在基于线段树的实现中,这个和是可以直接求得的. 但是如果我们能够计算(从1到t的和)-(从1到s-1的和),同样可以得到s到t的和.也就是说,只要对于任意i,我们都能计算出1