Apple Tree

Apple Tree

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 5
描述

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?

输入
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

题目大意:一棵苹果树(不一定是二叉树),每个节点有一个苹果, kaka的一次操作C可以摘一个节点的苹果或者使没有苹果的节点长出苹果, 查询的是某棵子树上的苹果总数。

思路:

明显的区间求和问题,可以用线段树和树状数组求解。 问题的关键在于把树存储在一维数组中,这个用一个深搜可以解决, 用三个数组data存每个点(重新排序的点)的数据, start[i] 表示原始节点i在data 里的位置, end[i] 表示原始节点i子树在data里的结束点, 所以求子树i的总苹果数就是start[i]到end[i]在data中所有数据的和。区间查询就是线段树或树状数组的基本操作了。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct Node
{
	int child;
	Node *next;
}Node;

Node node[100001];

int n, m, top = 0, data[100001], start[100001], end[100001];

void dfs(int pos)
{
	start[pos] = ++top;             //为所有节点重新编号, 并确定start,end数组的值
	Node *p = node[pos].next;
	while(p)
	{
		if(start[p->child] == 0)
		{
			dfs(p->child);
		}
		p = p->next;
	}
	end[pos] = top;
}

int lowbit(int x)                  //树状数组求点到区间临界距离的函数
{
	return x & (-x);
}
 
int getsum(int end)                //树状数组区间求和
{
	int sum = 0;
	while(end > 0)
	{
		sum += data[end];
		end -= lowbit(end);
	}
	return sum;
}

void change(int pos, int item)      //树状数组更改节点的值
{
	while(pos <= n)
	{
		data[pos] += item;
		pos += lowbit(pos);
	}
}

int main()
{
	int i, k, s, e, temp;
	char c;
	scanf("%d", &n);
	for(i = 1; i < n; i++)           //建立树
	{
		scanf("%d%d", &s, &e);
		Node *p = (Node *)malloc(sizeof(Node));
		p->child = e;
		p->next = node[s].next;
		node[s].next = p;
	}
	dfs(1);                                  //初始化那三个数组
	for(i = 1; i <= n; i++)
	{
		change(i, 1);
	}
	scanf("%d", &m);
	for(i = 0; i < m; i++)                   //查询
	{
		getchar();
		scanf("%c%d", &c, &k);
		if(c == 'C')
		{
			temp = getsum(start[k]);
			temp -= getsum(start[k]-1);
			if(temp)
			{
				change(start[k], -1);
			}
			else
			{
				change(start[k], 1);
			}
		}
		else
		{
			temp = getsum(end[k]);
			temp -= getsum(start[k]-1);
			printf("%d\n", temp);
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值