poj 3321

题意:一棵具有n个节点的树,一开始,每个节点上都有一个苹果。现在给出m组动态的操作:(C,i)是摘掉第i个节点上面的苹果(若苹果不存在,则为加上一个苹果),(Q,i)是查询以第i个节点为根的子树有几个苹果(包括第i个节点)。

 

思路:树状数组。这道题重点怎么建立树到树状数组的映射关系:利用dfs遍历树,对每个节点进行两次编号,第一次搜到第i个节点时的深度dep,为这个节点管辖区间的上限low[i](也为这个节点的下标),然后搜这个节点的子节点,最后搜回来后的深度dep,为这个节点管辖区间的下限high[i],如下图所示。接下来就是树状数组部分了。

代码:

#include<iostream>
#include<fstream>

using namespace std;

int n,m;

struct e{
	int data;
	e *next;
};

e edge[100001];

int node[100001];
int v[100001];
int b[100001];
int end[100001];
int sum;

void dfs(int s){
	int i,j,k;
	v[s]=++sum;
	e *p=edge[s].next;
	while(p){
		if(v[p->data]==0)
			dfs(p->data);
		p=p->next;
	}
	end[s]=sum;
}

int lowbit(int x){
	return x&(-x);
}

void add(int s,int t){
	while(s<=n)
	{
		b[s]+=t;
		s+=lowbit(s);
	}
}

int getsum(int s){
	int i=0;
	while(s>0)
	{
		i+=b[s];
		s-=lowbit(s);
	}
	return i;
}


void read(){
//	ifstream cin("in.txt");
	int i,j,k,s,t;
//	cin>>n;
	scanf("%d",&n);
	for(i=1;i<n;i++)
	{
//		cin>>s>>t;
		scanf("%d%d",&s,&t);
		e *p=new e;
		p->data=t;
		p->next=edge[s].next;
		edge[s].next=p;

		e *q=new e;
		q->data=s;
		q->next=edge[t].next;
		edge[t].next=q;
	}
	dfs(1);
	char c;
	for(i=1;i<=n;i++)
		add(i,1);
//	cin>>m;
	scanf("%d",&m);
	for(i=1;i<=m;i++)
	{
//		cin>>c>>j;
		getchar();
		scanf("%c%d",&c,&j);
		if(c=='C')
		{
			s=getsum(v[j]);
			s-=getsum(v[j]-1);
			if(s==1)
				add(v[j],-1);
			else
				add(v[j],1);
		}
		else
		{
			s=getsum(end[j]);
			s-=getsum(v[j]-1);
			cout<<s<<endl;
		}
	}
}

int main(){
	read();
	return 0;
}

转载于:https://www.cnblogs.com/zhaozhe/archive/2011/05/14/2046334.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值