题目:http://poj.org/problem?id=3321
题意:给定一个整数n,代表树的节点个数,在给出n-1条边(u,v),其中编号1是根节点,开始时每个节点的值都为1。有两种操作①C X 将节点x的值取非(1变0,0变1),②Q x查询x的子树(包括x)值的总和。
分析:题目说的(u,v),只告诉u和v是相连的,但我当有向边做的也AC了。。。无向边怎么做???树上的边都是有向的吧?
首先要把树建起来。建好后,修改节点的值好办,直接用树状数组log(n)修改,查询就不好办了,因为一个节点它的子树的编号可能是无序的,查询起来不方便。那么建树的时候把所有的节点重新编号就行了。。。查询的子树就是一段连续的区间了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1e5+5;
int trans[maxn],L[maxn],R[maxn];
bool f[maxn];
struct node
{
int pos;
int next;
};
int Table[maxn],cnt;
node List[maxn];
void Clear()
{
cnt=0;
memset(Table,-1,sizeof(Table));
}
void Insert(int Tbl,int v)
{
List[cnt].pos=v;
List[cnt].next=Table[Tbl];
Table[Tbl]=cnt++;
}
int cur,tree[maxn];
void DFS(int value)
{
trans[value]=++cur;
L[trans[value]]=cur;
int next=Table[value],i;
while(next>=0)
{
DFS(List[next].pos);
next=List[next].next;
}
R[trans[value]]=cur;
}
int lowbit(int x)
{
return x&-x;
}
void update(int x,int c)
{
for(int i=x;i<=cur && i;i+=lowbit(i))
tree[i]+=c;
}
int query(int x)
{
int ret(0);
for(int i=x;i>0;i-=lowbit(i))
ret+=tree[i];
return ret;
}
int main()
{
int n,u,v,m,c;
char str[20];
while(scanf("%d",&n)!=EOF)
{
Clear();
memset(tree,0,sizeof(tree));
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
Insert(u,v);
}
cur=0;
DFS(1);
memset(f,true,sizeof(f));
for(int i=1;i<=cur;i++)
update(i,1);
scanf("%d",&m);
while(m--)
{
scanf("%s%d",str,&c);
if(str[0]=='Q')
printf("%d\n",query(R[trans[c]])-query(L[trans[c]]-1));
else
{
if(f[trans[c]])
{
update(trans[c],-1);
f[trans[c]]=false;
}
else
{
update(trans[c],1);
f[trans[c]]=true;
}
}
}
}
return 0;
}