poj-3321(dfs+树状数组)

http://acm.hust.edu.cn:8080/judge/problem/viewProblem.action?id=10486

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

[]中的第一个数,为树中这个点映射到线性数组中的所在位置。例如[1,5]中的1代表着映射之后,树的第一个结点在数组中也是第一个位置;

poj <wbr>3321 <wbr>: <wbr>Apple <wbr>Tree <wbr>(树状数组)

#include<iostream>
using namespace std;
#define max 100005
struct 
{
	int u,v,next;
}t[max];
int low[max],high[max],c[max],n,first[max],h;
int lowbit(int x)
{
	return x&(-x);
}
void updata(int i,int j)
{
	while(i<=n)
	{
		c[i]+=j;
		i+=lowbit(i);
	}
}
int getsum(int x)
{
	int sum=0;
	while(x>0)
	{
		sum+=c[x];
		x-=lowbit(x);
	}
	return sum;
}
void dfs(int u)                             //将树形结构映射成线性结构
{
	low[u]=++h;                             
	for(int i=first[u];i!=-1;i=t[i].next)        //first这个数组用来判断循环是否结束,当==-1则结束
	{
		dfs(t[i].v);                              //要是first数组!=-1,说明此处树有子节点,那么需要转换;i=t[i].next结点之后
	}                                          //(first结点的值==u或者-1的)所以要历遍玩first结点(t[i].u结点)后,还要历遍
	high[u]=h;                             //t[i].u后面的t[i].v结点
}
int main()
{
	while(scanf("%d",&n)>0)
	{
		memset(first,-1,sizeof(first));
		memset(c,0,sizeof(c));
		int i,k=0;
		for(i=0;i<n-1;i++)              //建树
		{
			int u,v;
			scanf("%d%d",&u,&v);
			k++;
			t[k].u=u;
			t[k].v=v;
			t[k].next=first[u];                 //让这一个结点连在下一个结点之后
			first[u]=k;                    //在dfs中,方便转换
		}
		for(i=1;i<=n;i++)             //初始值全部为1
			updata(i,1);
		h=0;
		dfs(1);
		int m;
		scanf("%d",&m);
		while(m--)
		{
			char s[5];
			int tmp;
			scanf("%s%d",s,&tmp);
			if(s[0]=='Q')
			{
				printf("%d\n",getsum(high[tmp])-getsum(low[tmp]-1));
			}
			else
			{
				int ans=getsum(low[tmp])-getsum(low[tmp]-1);      //在思路里面已经说了,low[tmp]代表的是树的第tmp个结点  
				if(ans==0)
					ans=1;
				else
					ans=-1;
				updata(low[tmp],ans);
			}
		}
	}
	return 0;
}

 

posted @ 2012-12-23 17:31  紫忆  阅读(244)  评论(0编辑  收藏  举报