http://poj.org/problem?id=3321
题目大意:
给你N个点组成的树 每个点初始化为1 有两种操作
C x:改变点的值 是1变0 是0变1
Q x:问以x为根的子树上点值的和
思路:
主要是把树映射到树状数组中
一遍dfs把点重新编号 low和high low表示刚搜到此点时的计数,high是搜玩其子树内所有节点后回来的计数编号
比如说又n个点那么根节点1的low=1,high=2*n
这样就映射到树状数组中啦。
代码及其注释:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<algorithm>
#include<stack>
using namespace std;
const int N=100010;
struct node
{
struct tt *next;
}mem[N];
struct tt
{
struct tt *next;
int j;
};
int n,I;//n is the number of apples I 是全局计数
int c[N*2];
int high[N];
int low[N];
bool visited[N];
int apple[N];//某个点是否有苹果
void build(int i,int j)//建树
{
struct tt *t=new tt;
t->j=j;
t->next=mem[i].next;
mem[i].next=t;
}
void dele()//一定的清理
{
for(int i=1;i<=n;++i)
mem[i].next=NULL;
}
int lowbit(int x)
{
return x&(-x);
}
void Add(int x,int k)
{
for(int i=x;i<=2*n;i+=lowbit(i))
{
c[i]+=k;
}
}
int Sum(int x)
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
{
sum+=c[i];
}
return sum;
}
void dfs(int x)//深搜 计数
{
visited[x]=true;
++I;
low[x]=I;
struct tt *t=new tt;
t=mem[x].next;
while(t!=NULL)
{
if(visited[t->j]==false)
{
dfs(t->j);
}
t=t->next;
}
++I;
high[x]=I;
}
int main()
{
int m;
while(scanf("%d",&n)!=EOF)
{
memset(c,0,sizeof(c));
for(int i=1;i<n;++i)
{
int l,r;
scanf("%d %d",&l,&r);
build(l,r);
build(r,l);
}
I=0;
memset(visited,false,sizeof(visited));
dfs(1);
for(int i=1;i<=n;++i)
{
apple[i]=1;
}
for(int i=1;i<=2*n;++i)
{
Add(i,1);//初始化树状数组
}
scanf("%d",&m);
while(m--)
{
char c;
int k;
getchar();
scanf("%c %d",&c,&k);
if(c=='Q')
{
printf("%d\n",(Sum(high[k])-Sum(low[k]-1))/2);
}else
{
if(apple[k]==1)
{
apple[k]=0;
Add(low[k],-1);
Add(high[k],-1);
}
else
{
apple[k]=1;
Add(low[k],1);
Add(high[k],1);
}
}
}
dele();
}
return 0;
}