POJ 3321 树状数组

本文介绍了一种使用树状数组结合深度优先搜索(DFS)的方法来解决涉及动态更新树中节点属性的问题。具体地,通过为树的每个节点标记时间戳并利用树状数组快速查询区间和,从而高效处理子树上节点数量的查询及苹果的增删操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给定一棵树,某些节点上有苹果,多次询问各子树上的节点数,并且在询问的中途随时可能新增和删除苹果。

分析:dfs遍历树的同时,对每个点标注时间,每个点有一个开始时间和一个结束时间,把这两个时间当做下标,该点的苹果个数(1或0)填入数组的两个对应位。子树中结点的时间段一定是根节点时间段的子段,所以求子树苹果数,只需求数组某区间的和即可。用树状数组比较快。

#include<cstdio>
#include<cstring>
const int n_max=200005;
int n,a[n_max],ne,N;
int head[n_max],cnt;
int apple[n_max],pos[n_max];

struct Node
{
	int v,last;
}e[n_max];

struct Root
{
	int begin,end;
}p[n_max];

void addedge(int x,int y)
{
	e[ne].v=y;
	e[ne].last=head[x];
	head[x]=ne;
	ne++;
}

void bfs(int num)
{
	p[num].begin=cnt;
	int i;
	for(i=head[num];i!=-1;i=e[i].last)
	{
		bfs(e[i].v);
	}
	pos[num]=cnt;
	p[num].end=cnt++;
}

void insert(int k,int p)
{
	while(k<=N)
	{
		a[k]+=p;
		k+=k&(-k);
	}
}

int sum(int k)
{
	int ret=0;
	while(k>0)
	{
		ret+=a[k];
		k-=k&(-k);
	}
	return ret;
}

int main()
{
	while(~scanf("%d",&n))
	{
		ne=0;
		memset(head,-1,sizeof(head));
		int i,x,y;
		for(i=1;i<n;i++)
		{
			scanf("%d%d",&x,&y);
			addedge(x,y);
		}
		cnt=2;
		N=n+1;
		bfs(1);
		for(i=1;i<=n;i++)
		{
			apple[i]=1;
			insert(pos[i],1);
		}
		int m,t;
		char op[10];
		scanf("%d",&m);
		while(m--)
		{
			scanf("%s%d",op,&t);
			if(op[0]=='Q')
			{
				printf("%d\n",sum(p[t].end)-sum(p[t].begin-1));
			}
			else
			{
				int temp;
				if(apple[t]==1)
				{
					temp=-1;
				}
				else
				{
					temp=1;
				}
				insert(pos[t],temp);
				apple[t]+=temp;
			}
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值