POJ 3321(dfs序+树状数组)

题意:一棵苹果树有n个结点,编号从1到n,根结点永远是1。该树有n-1条树枝,每条树枝连接两个结点。已知苹果只会结在树的结点处,而且每个结点最多只能结1个苹果。初始时每个结点处都有1个苹果。树的主人接下来会进行m个操作。操作共两种。C X表示将结点x上的苹果数量改变,原本是1,则现在为0,原本是0,现在是1。Q X表示一次查询。要求输出结点X和其子树上的苹果总数。n和m最大可到100000。


显然可以用树状数组更新求和,但是题目中是树状结构,而一般树状数组的范围是用来求一段区间和的。所以需要考虑的就是如何把树形结构转换为线性【即一段区间】,然后进行普通树状数组的操作即可。


这里转换过程用到了一个小技巧,记录时间戳。方法是,采用dfs对树进行一次遍历,树的每一个结点都有st和ed两个时间戳,分别记录该结点被遍历到的时间戳以及它和它的子树全部遍历完后的时间戳。举一个例子来说明

 然后这就化成了一段区间,下来就可以进行区间求和和更新维护的操作了。


求和:if(ch=='Q') printf("%d\n",getsum(end[num])-getsum(start[num]-1));

然后还有就是修改点权,1变0,0变1.


代码如下:


你可能感兴趣的:(POJ 3321(dfs序+树状数组))