http://acm.hust.edu.cn:8080/judge/problem/viewProblem.action?id=10486
思路:树状数组。这道题重点怎么建立树到树状数组的映射关系:利用dfs遍历树,对每个节点进行两次编号,第一次搜到第i个节点时的深度dep,为这个节点管辖区间的上限low[i](也为这个节点的下标),然后搜这个节点的子节点,最后搜回来后的深度dep,为这个节点管辖区间的下限high[i],如下图所示。接下来就是树状数组部分了。
[]中的第一个数,为树中这个点映射到线性数组中的所在位置。例如[1,5]中的1代表着映射之后,树的第一个结点在数组中也是第一个位置;
#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;
}