您的位置:首页 > 移动开发

【树状数组】 ◆POJ 3321◆ Apple Tree

2018-02-06 21:40 375 查看

◆POJ 3321◆(2007 POJ Monthly Contest, Aug.)

Apple Tree

◆题目◆

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

The tree has N forks which are connected by branches. Kaka numbers the forks by 1 to N and 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?



Input

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

Output

For every inquiry, output the correspond answer per line.

Sample Input

3
1 2
1 3
3
Q 1
C 2
Q 1


Sample Output

3
2


◆大致翻译◆

描述

卡卡家外面有一棵苹果树,苹果树上长了很多很多滴苹果。卡卡超级喜欢苹果,所以,他一直很小心的照顾这棵大苹果树。

这个树上有N个通过枝干连接起来的叉叉。卡卡给这些叉叉编号1,2,…,N,根的标号为1。苹果长在叉叉上,并且不会有两个苹果长在同一个叉叉上。每个叉上刚开始都有一个苹果.卡卡为了研究这棵苹果树的生产能力,他想知道有好多苹果长在一棵子树上。

麻烦的是,有时候,一个新的苹果会在一个未结苹果的空叉叉上长出来,有时候,卡卡又会爬到树上去摘一个苹果来吃。

你能帮卡卡吗?

输入

第一行为一个整数N(N<=100,000),表示这棵树上有多少个叉叉。

接下来的N-1行,每行包括两个数字u和v,表示叉叉u和叉叉v有一条枝干连接着它们。

下一行为一个整数M(M<=100,000)。

接下来M行,每行的信息为以下两种之一:

“C x”表示叉叉x上的状态会改变。如果叉叉x上有苹果,卡卡会摘了他,如果没苹果,这个叉叉上会新长一个苹果出来。

“Q x”表示询问以叉叉x为根的这棵子树上有多少个苹果,如果叉叉x上有苹果,也要算进去。

输出

对于每个询问,输出相符的答案,占一行。

copy from the OJ of my school

◆解析◆

众所周知,树状数组和线段树密不可分,有许多题能同时用树状数组和线段树解决(比如这道题)。

作者已经点出来了——这道题运用的是树状数组或线段树,掌握其中一种即可,但是我只写了一种。

树状数组相对于线段树代码要简洁得多,但是不知大家有没有看出来这其实可以用树状数组来做呢?

a)DFN(Deep First Number)

这道题的输入是树形结构,但是树状数组其实是一个链表的树状化,本质还是一个一维数组。那么我们就需要给每一个“叉叉”编码使其能够连续地出现在一个链表上。

这里用到的就是深度优先编号(DFN)。顾名思义,该编码是通过深度优先搜索来实现的——每个节点编号有两个:In、Out。In和Out分别表示了以当前节点为根的子树的起始点和终止点。结合代码来理解一下:

void Search(int x)
{
flag[x]=true;
F[x][0]=++tot;flag[x]=true;
for(int i=0;i<vec[x].size();i++)
if(!flag[vec[x][i]])
Search(vec[x][i]);
F[x][1]=tot;
}


Search是一个递归函数——进入时更新 In,递归回来时更新 Out。举个例子:

下图展示了一个编码的递归过程(蓝色是节点编的号,绿色是往下递归时传入的tot_get,红色是递归结束返回的tot_ret):



那么就可以得到以i为根的子树的编码区间:

eg:(原数)2:表示的区间是 [tot_get=2 , tot_ret=5]

这样有几个好处:①将多叉树转换为二叉树;②将以某个点作为根的子树的元素从零散改为连续(eg:原本以3为根的子树的元素有3,6,7,9,10 编码后为 6,7,8,9,10)。

b)树状数组

(以下的F[i][0~1]表示以i为根的子树表示的区间)

由于编码是连续的,我们可以直接把F[i]压入一个链表,作为树状数组的原数组。

而且通过编码我们能够得到一个区间,所以求以i为根的子树的大小只需要计算(sum()为前缀和)

sum(F[i][1])−sum(F[i][0]−1)sum(F[i][1])−sum(F[i][0]−1)

相信树状数组的基本结构大家都知道吧O(∩_∩)O~~

◆代码◆

下面附上作者Gitee的代码:

树状数组的代码

The End

Thanks for Reading!

-Lucky_Glass
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  树状数组 POJ DFN编码