题目链接:http://poj.org/problem?id=3321
大致题意:给你一棵树,有n个点,每个点初始时权值为1,有两种操作:
(1)C x :若节点x的权值为1,则将其变为0,否则将其变为1
(2)Q x :查询点x的所有子节点(包括x)的权值和
dfs序模板题,巧妙的利用dfs序的性质
DFS序: 就是DFS整棵树依次访问到的结点组成的序列
DFS序性质: 一颗子树的所有节点在DFS序内是连续的一段
剩下的就是区间求和问题了,用树状数组随便搞搞
这题还有个坑点是建边是单纯的vector会超时,需要建双重容器Orz(重要的是这题的方法,没去深究)
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<math.h>
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
typedef long long ll;
#define inf 10000000
#define mod 1000000007
#define maxn 200005
#define lowbit(x) (x&-x)
#define eps 1e-10
int n,vis[maxn],ed[maxn],st[maxn],s[maxn],cnt;
vector<vector<int> > q(maxn);
void dfs(int x)//求dfs序
{
st[x]=cnt;
for(int i=0;i<q[x].size();i++)
{
cnt++;
dfs(q[x][i]);
}
ed[x]=cnt;
}
void add(int x,int y)
{
while(x<=n)
{
s[x]+=y;
x+=lowbit(x);
}
}
int sum(int x)
{
int res=0;
while(x>0)
{
res+=s[x];
x-=lowbit(x);
}
return res;
}
int main(void)
{
char c[5];
int i,j,x,y,m;
while(~scanf("%d",&n))
{
memset(s,0,sizeof(s));
memset(st,0,sizeof(st));
memset(ed,0,sizeof(ed));
memset(vis,0,sizeof(vis));
for(i=0;i<maxn;i++)
q[i].clear();
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
q[x].push_back(y);
}
for(i=1;i<=n;i++)
add(i,1);
cnt=1;dfs(1);
scanf("%d",&m);
while(m--)
{
scanf("%s%d",c,&x);
if(c[0]=='Q')
printf("%d\n",sum(ed[x])-sum(st[x]-1));
else
{
if(vis[x])
add(st[x],1);
else
add(st[x],-1);
vis[x]=1-vis[x];
}
}
}
return 0;
}