题面
【题目描述】
有一棵苹果树,苹果产量特别高,这棵树有
n
n
n个分叉点,并且它们之间有树枝相连,将这些分叉点编号,并且树根一直都是
1
1
1,苹果会长在枝条的分叉点上面,且不会有两个苹果结在一起。你想要对它进行统计,但是有些小朋友会摘掉其中的一些苹果,而有的时候,苹果又会长出来。
于是我们定义两种操作:
C
C
C
x
x
x,表示编号为
x
x
x的分叉点的状态被改变(原来有苹果的话,就被摘掉,原来没有的话,就结出一个苹果)
Q
Q
Q
x
x
x,查询编号为x的分叉点所代表的子树中有多少个苹果
我们假定一开始的时候,树上全都是苹果,也包括作为根结点的分叉
1
1
1。
【输入】
第一行一个数
N
N
N (
n
≤
100000
n\leq 100000
n≤100000)
接下来
n
−
1
n-1
n−1行,每行
2
2
2个数u,v,表示分叉点u和分叉点v是直接相连的。
再接下来一行一个数
M
M
M(
M
≤
100000
M\leq 100000
M≤100000),表示询问数
接下来
M
M
M行,表示询问,询问的格式如题目所述
Q
Q
Q
x
x
x或者
C
C
C
x
x
x。
【输出】
对于每个
Q
Q
Q
x
x
x的询问,请输出相应的结果,每行输出一个
【样例输入】
3
1 2
1 3
3
Q 1
C 2
Q 1
【样例输出】
3
2
【数据范围】
20
%
:
n
≤
100
20\%:n\leq 100
20%:n≤100
40
%
:
n
≤
3000
40\%:n\leq 3000
40%:n≤3000
100
%
:
n
≤
00000
100\%:n\leq 00000
100%:n≤00000
算法分析
本题是对树进行操作,可以使用dfs序将树形结构转换为线性结构。详解dfs序
询问子树的和,对应线性结构的区间和。
修改结点的值,对应线性结构的单点修改。
参考程序
#include<bits/stdc++.h>
#define N 100010
using namespace std;
int n,m,c[N],inn[N],outt[N],id[N],timee,vis[N];
struct node
{
int to;
int nxt;
int w;
}edge[2*N];
int head[N],t;
void Add(int u,int v)
{
edge[++t].nxt=head[u];
head[u]=t;
edge[t].to=v;
}
void dfs(int u) //dfs序
{
inn[u]=++timee; //入栈时间
id[u]=timee; //新的线性序列编号
vis[u]=1;
for(int i=head[u];i!=-1;i=edge[i].nxt)
{
int v=edge[i].to;
if(!vis[v]) dfs(v);
}
outt[u]=timee;//出栈时间,出栈不算时间
}
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int val)
{
for(int i=x;i<=n;i+=lowbit(i))
c[i]+=val;
}
int sum(int x)
{
int ans=0;
for(int i=x;i>0;i-=lowbit(i))
ans+=c[i];
return ans;
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d",&n);
int u,v;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
Add(u,v);
Add(v,u);
}
dfs(1);
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
update(i,1);
scanf("%d",&m);
char s[10];
int x;
for(int i=1;i<=m;i++)
{
scanf("%s%d",s,&x);
if(s[0]=='Q') printf("%d\n",sum(outt[x])-sum(inn[x]-1));
else
{
if(vis[x]) update(id[x],1),vis[x]=0; //1表示没有,0表示有
else update(id[x],-1),vis[x]=1; //对新的线性序列进行修改,为id[x]
}
}
return 0;
}