苹果树
题面
题目描述
卡卡家门外有一棵苹果树。每年秋天,树上都会种很多苹果。卡卡非常喜欢苹果,因此他一直在精心培育大苹果树。
该树有 \(n\) 个分叉,这些分叉由树枝连接。卡卡用 \(1\) 到 \(n\) 对分叉进行编号,并且根始终用 \(1\) 编号。在叉上将生长苹果,而在同一叉上将不会生长出两个苹果。卡卡想了解某个子树中有多少个苹果,以便研究苹果树的结果能力。
问题在于,有时候,一个空叉上会长出一个新苹果,或者卡卡可能会从树上摘下一个苹果作为甜点。你能帮卡卡吗?
输入格式
第一行包含一个整数 \(n\) ,代表分叉数量。
接下来 \(n−1\) 行分别包含两个整数 \(u,v\) ,意味着分支 \(u\) 和分支 \(v\) 通过一个树枝连接
下一行包含一个整数 \(m\)
接下来 \(m\) 行分别包含一个操作
C x,这代表着在分叉 \(x\) 上苹果的存在状态发生更改。也就是如果分叉上有一个苹果,则卡卡摘下;否则,空叉上会长出一个新苹果。
Q x,表示查询分叉 \(x\) 上方子树中的苹果数量,请注意,开始时树上结满了苹果
输出格式
对于每一个询问,输出一行一个答案
输入样例
3
1 2
1 3
3
Q 1
C 2
Q 1
输出样例
3
2
数据范围
\(1≤N,M≤100,000\)
\(1≤u,v≤n\)
题解:
看到这个询问方式,很容易联想到 线段树。
对于树上问题,我们可以通过dfs序转换为区间问题。
那么代码就显而易见了:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int M=4e5+5;
struct edge{
int to,nxt;
}e[M];
int head[M],sum[M],vis[M],in[M],out[M],n,q,cnt,res;
int ll[M], rr[M];
void add(int u,int v){
e[++cnt]=(edge){v,head[u]};
head[u]=cnt;
}
void dfs(int u){
in[u]=++res;
vis[u]=1;
ll[u] = rr[u] = res;
for(int i=head[u];i;i=e[i].nxt){
if(vis[e[i].to])continue;
dfs(e[i].to);
ll[u] = min(ll[u], ll[e[i].to]);
rr[u] = max(rr[u], rr[e[i].to]);
}
out[u]=res;
}
inline int read(){
int x=0,f=1;
char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0' && c<='9'){
x=x*10+c-48;
c=getchar();
}
return x*f;
}
void Build(int l,int r,int t){
if(l==r){
sum[t]=1;
return;
}
int mid=l+r>>1;
Build(l,mid,t<<1);
Build(mid+1,r,t<<1|1);
sum[t]=sum[t<<1]+sum[t<<1|1];
}
int que(int l,int r,int t,int x,int y){
int ans = 0;
if(l > y or r < x) return 0;
if(l>=x&&r<=y){
ans+=sum[t];
return ans;
}
int mid=l+r>>1;
if(x<=mid) ans+=que(l,mid,t<<1,x,y);
if(y>mid) ans += que(mid+1,r,t<<1|1,x,y);
return ans;
}
void change(int pos,int l,int r,int t){
if(l==r){
sum[t]=1-sum[t];
return;
}
int mid=l+r>>1;
if(pos<=mid) change(pos,l,mid,t<<1);
else change(pos,mid+1,r,t<<1|1);
sum[t]=sum[t<<1] + sum[t<<1|1];
}
signed main(){
n=read();
for(int i=1;i<n;i++){
int u=read(),v=read();
add(u,v);
add(v,u);
}
Build(1,n,1);
dfs(1);
q=read();
while(q--){
char x=getchar();
int u=read();
if(x=='C')change(in[u],1,n,1);
else printf("%lld\n",que(1,n,1,ll[u],rr[u]));
}
// system("PAUSE");
}