Apple Tree

来源:互联网 发布:淘宝账号已被冻结 编辑:程序博客网 时间:2024/05/16 17:48

OpenJudge 树状数组练习题 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
"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
"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.

样例输入

31 21 33Q 1C 2Q 1
样例输出

32


分析

题目样例和图给的树是二叉树,这很容易让人以为树都是二叉树。但题目并没有指定树的形式,也就是说,树还可以是其它类型的多叉树。当用树状数组来解题时,我们希望能直接通过树状数组记录的值计算出结果。由于树状数组的每一个元素记录的某一段的和,如果我们按前序访问的顺序(先访问根节点,再从左至右依次访问子树)将所有fork排成一列以形成一个序列(下标从1开始),并对这个序列建立一个树状数组,那么对于该序列的每一个前缀a1,a2,……,ai,我们就可以根据树状数组计算出前缀和sum[i](苹果总数)。对于每个fork(节点),如果我们能够确定它及其子树在序列中占据的位置是区间[l,r],那么sum[k]-sum[l-1]就是我们需要求的苹果数。


AC代码

#include <iostream>#include <vector> using namespace std;int cnt, *l, *r;vector<int> tree[100001];void set_edge(int i){l[i] = ++cnt;     //左端点下标 for (int j = 0; j < tree[i].size(); ++j)     //设置子树 set_edge(tree[i][j]);r[i] = cnt;     //右端点下标 }int main(){char op;bool TorF[100001];    //fork x是否有apple int n, m, u, v, x, sum, suml, k, i;int left[100001], right[100001], c[100001];   //每个fork占据区间的左、右端点,树状数组c cin >> n;      //n forks for (i = 1; i < n; ++i)     //输入n-1组u、v {cin >> u >> v;tree[u].push_back(v);}cnt = 0;      //初始化 l = left;r = right;set_edge(1);      //设置每个以fork为根结点的树所占据的区间的左右端点 for (i = 1; i <= n; ++i)    //初始化c和TorF(初始时每个fork都有apple) {c[i] = i&(-i);TorF[i] = 1;}cin >> m;       //m个操作 while (m--){cin >> op >> x;        //输入操作 if (op == 'C')     //change操作 {int temp;if (TorF[x] == 1)      //原来有apple {temp = -1;TorF[x] = 0;}else       //原来没apple {temp = 1;TorF[x] = 1;}x = left[x]; while (x <= n)      //更新父节点 {c[x] += temp;x += (x&(-x));}}else       //inquiry操作 {sum = suml = 0;k = right[x];while (k)       //区间[1,right[x]]的apple数 {sum += c[k];k -= (k&(-k));}k = left[x]-1;while (k)      //区间[1,left[x]-1]的apple数 {suml += c[k];k -= (k&(-k));}cout << sum-suml << endl;       //输出结果(区间[left[x]-1,right[x]]的apple数 }}return 0;}


原创粉丝点击