数算实习树状数组作业POJ :Apple Tree

题目

描述
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 carefully nurturing the big apple tree.

The tree has Nforks which are connected by branches. Kaka numbers the forks by 1 to Nand the root is always numbered by 1. Apples will grow on the forks and two apple won’t grow on the same fork. kaka wants to know how many apples are there in a sub-tree, for his study of the produce ability of the apple tree.

The trouble is that a new apple may grow on an empty fork some time and kaka may pick an apple from the tree for his dessert. Can you help kaka?

输入
The first line contains an integer N (N ≤ 100,000) , which is the number of the forks in the tree.
The following N - 1 lines each contain two integers u and v, which means fork u and fork v are connected by a branch.
The next line contains an integer M (M ≤ 100,000).
The following M lines each contain a message which is either
“C x” which means the existence of the apple on fork x has been changed. i.e. if there is an apple on the fork, then Kaka pick it; otherwise a new apple has grown on the empty fork.
or
“Q x” which means an inquiry for the number of apples in the sub-tree above the fork x, including the apple (if exists) on the fork x
Note the tree is full of apples at the beginning

输出
For every inquiry, output the correspond answer per line.

样例输入
3
1 2
1 3
3
Q 1
C 2
Q 1
样例输出
3
2

分析与思路

课程PPT截图
主要思路就是图中的课件所言。

为了应用树状数组的算法,我们需要将具体问题中的元素与模板做个对应。在这道题中查询的是苹果的数量,这一点求和似乎可以用树状数组来做,但本题中的原始数组并不明显,在这里采用dfs的办法编制一个原始数组的顺序(很巧妙,完美解决了父子节点间的关系问题),当然在dfs之前我们要把这些父子关系用数据结构存起来,如果直接用多维数组的话需要开的数组过大会溢出(总之运行不了),考虑到一个父节点可能只有几个子节点这种情况,选择用vector<vector< int>>存储比较合适,有需要直接push_back就可以,只是需要注意一下初始化数组的时候默认给了一个0元素,在dfs的时候需要从adj_mat[i].begin()+1开始。用二维数组times[100010][2]将各个节点对应的开始和结束时间记录下来以便后续查询。
至此我们得到了原始数组,因为在本题中初始状态节点上均有一个苹果,所以在构建树状数组C的时候可以讨个巧,
C [ i ] = i − ( i − l o w b i t ( i ) + 1 ) + 1 = l o w b i t ( i ) C[i]=i-(i-lowbit(i)+1)+1=lowbit(i) C[i]=i(ilowbit(i)+1)+1=lowbit(i)
用来直接替代原本累加的循环

所以现在我们也有了初始的的树状数组,接下来单点更新和查询的函数直接套用算法模板就可以完成。

犯错点

  1. 在单点更新树状数组的时候,开始选择了对ori数组更新后将涉及到的C[i]置0后重新累加,带来了极高的复杂度,但实际上只需要对涉及到的C[i]元素加上相应的增量就能解决问题。
  2. 位置0对于树状数组建树来说会带来一些麻烦(主要是因为lowbit),所以尽量从使数组中的元素从位置1开始

代码

#include<iostream>
#include<vector>
using namespace std;
#pragma warning(disable:4996)
//邻接表,做深搜,记录对应时间点,安进去,
//生成树状数组,写更新函数,写求和函数
int lowbit(int x) {
	return x & (-x);
}
vector<vector<int>> adj_mat(100010, { 0 });
int times[100010][2] = { 0 };
int ori[200020] = { 0 };
int C[200020] = { 0 };
int N = 0;
int t = 1;
void dfs(int a) {
	times[a][0] = t;
	t++;
	for (auto i = adj_mat[a].begin() + 1; i != adj_mat[a].end(); i++)
	{

		dfs(*i);
		t++;
	}
	times[a][1] = t;
}
int sum(int k) {
	int res = 0;
	while (k != 0)
	{
		res += C[k];
		k -= lowbit(k);
	}
	return res;
}
void change(int b) {
	int ch[2] = { times[b][0],times[b][1] };
	for (int i = 0; i < 2; i++)
	{
		int temp = ch[i];
		if (ori[temp] == 1) {
			ori[temp] = 0;
			while (temp <= t)
			{
				C[temp] -= 1;
				temp = temp + lowbit(temp);
			}
		}
		else {
			ori[temp] = 1;
			while (temp <= t)
			{
				C[temp] += 1;
				temp = temp + lowbit(temp);
			}
		}
	}
}
int main() {
	cin >> N;
	for (int i = 1; i <=2*N; i++)
	{
		ori[i] = 1;
	}

	for (int i = 0; i < N - 1; i++)
	{
		int a, b;
		scanf("%d%d", &a, &b);
		adj_mat[a].push_back(b);
	}//完成邻接表
	dfs(1);//完成dfs
	for (int i = 1; i <= t; i++)
		C[i] +=lowbit(i);
	//生成树状数组
	int M;
	cin >> M;
	for (int i = 0; i < M; i++)
	{
		char a;
		int b;
		scanf("\n%c %d", &a, &b);
		if (a == 'Q') {
			printf("%d\n", (sum(times[b][1]) - sum(times[b][0] - 1)) / 2);
		}
		else if (a == 'C') {
			change(b);
		}
	}

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值