POJ 3321

Apple Tree 题目大意:有一颗苹果树,里面有n个节点,由n-1条边连接,形成一个树状关系,每一个节点有一个苹果,输入会将某个节点的苹果摘取或者添加,问单个节点及其子节点总共的苹果个数。思路:非常王道的思路,dfs序加上树状数组,这里就要说一下dfs序,顾名思义加上深度搜索的搜索路径记录成一个序列,其目的就是为了管理每一个节点的子节点,具体的情况可以看下图相信深搜你会了吧(如果不会就去重修数据结构),其实按照这个结果我们就可以看出些东西了。每一个节点都会出现两次,..
摘要由CSDN通过智能技术生成

Apple Tree

题目大意:

有一颗苹果树,里面有n个节点,由n-1条边连接,形成一个树状关系,每一个节点有一个苹果,输入会将某个节点的苹果摘取或者添加,问单个节点及其子节点总共的苹果个数。

思路:

非常王道的思路,dfs序加上树状数组,这里就要说一下dfs序,顾名思义加上深度搜索的搜索路径记录成一个序列,其目的就是为了管理每一个节点的子节点,具体的情况可以看下图

在这里插入图片描述

在这里插入图片描述

相信深搜你会了吧(如果不会就去重修数据结构),其实按照这个结果我们就可以看出些东西了。每一个节点都会出现两次,两次的中间所包括的都是其子节点,这样我们使用树状数组和线段树的时候就可以更好的遍历空间。对于一棵树的dfs序而言,同一棵子树所对应的一定是dfs序中连续的一段,具体还是看代码吧。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int max1=1e5+1;
vector<vector<int> > dp(max1);
int begin[max1],end[max1],tree[max1],c[max1];
int n,m,time;
void dfs(int k)
{
	time++;
	begin[k]=time;//保存其dfs序的开始 
	for(int i=0;i<dp[k].size();i++)
	{
		dfs(dp[k][i]);
	}
	end[k]=time;//保存其dfs序的结束 
}
//数状数组的模板 PS:和我的模板有一些不一样,这是比较简化版本 
int lowbit(int x)
{
	return x & -x;
}
void add(int x,int k)
{
	while(x<=n)
	{
		tree[x]+=k;
		x+=lowbit(x);
	}
}
int look(int x)
{
	int ans=0;
	while(x>0)
	{
		ans+=tree[x];
		x-=lowbit(x);
	}
	return ans;
}
int main()
{
	while(~scanf("%d",&n))
	{
		time=0;
		for(int i=1;i<=n-1;i++)
		{
			int a,b;
			scanf("%d %d",&a,&b);
			dp[a].push_back(b);//保存每一个节点的子节点 
		}
		dfs(1);//dfs得出dfs序 
		for(int i=1;i<=n;i++)
		{
			add(i,1);//树状数组设初值 
			c[i]=1;//判断节点是否有苹果 
		}
		scanf("%d",&m);
		while(m--)
		{
			int t;
			char q[12];
			scanf("%s%d",q,&t);
			if(q[0]=='Q'){
				printf("%d\n",look(end[t])-look(begin[t]-1));//从dfs序的结尾减去开头正好是中间我们所需要的值 
			}else{//拿走与添加苹果 
				if(c[t]){
					add(begin[t],-1);c[t]=0;
				}else{
					add(begin[t],1);c[t]=1;
				}
			}
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值