POJ3321 Apple tree【树状数组】

POJ3321 Apple tree【树状数组】_第1张图片

题目大意

一个有n个节点的树,树的每个节点可能有一个苹果或没有,有两种操作:
Cx 将节点x的权值改变,即如果有一个苹果删掉,否则增加一个苹果。
Qx 询问以节点x为根的子树中有多少个苹果。

思路

首先了解一下dfs序
对于棵树进行 d f s dfs dfs 遍历,
并记录每一个点的 d f s dfs dfs 序号 s t [ i ] st[i] st[i]
在一个节点的所有儿子都被遍历过后,
记录当前 e n [ i ] en[i] en[i] 为当前最大 d f s dfs dfs 序号的节点的 d f s dfs dfs 序号。
如图:
POJ3321 Apple tree【树状数组】_第2张图片
这样我们将问题转化为了区间操作
Cx 将某一点的权值改变
Qx 询问区间 [ s t [ x ] , e n [ x ] ] [st[x], en[x]] [st[x],en[x]] 的和
树状数组可以轻松实现这些操作。

代码

#include
#include
#include
#include
#include
using namespace std;
long long boss[1000010],ls[1000010],st[1000100],en[1000100],c[1000010],v[1000010];
long long n,x,y,tot,m;
char b;
struct node
{
	long long y,next;
}a[1000010];
void ljb(long long x,long long y)
{
	a[++tot].y=y;
	a[tot].next=ls[x];
	ls[x]=tot;
}
void dfs(long long x)
{
	tot++;
	st[x]=tot;
	for(long long i=ls[x]; i; i=a[i].next)
	   dfs(a[i].y);
	en[x]=tot;
}
long long lowbit(long long x)
{
	return x&(-x);
}
void query(long long x,long long s)
{
	for(; x<=n; x+=lowbit(x))
	   c[x]+=s;
}
long long find(long long x)
{
	long long ans=0;
	for(; x; x-=lowbit(x))
	   ans+=c[x];
	return ans;
}
int main()
{
    scanf("%lld",&n);
    for(long long i=1; i<n; i++)
     {
     	scanf("%lld%lld",&x,&y);
     	ljb(x,y);
     }
    tot=0;
    dfs(1);
    for(long long i=1; i<=n; i++)//苹果上树
     {
        v[i]=1;
        query(st[i],1);
     }
	scanf("%lld",&m);
    for(long long i=1; i<=m; i++)
     {
     	cin>>b;
		scanf("%lld",&x);
     	if(b=='C')
     	 {
     	 	if(v[x]==1)
     	 	 	query(st[x],-1);  //删
     	 	else
			   	query(st[x],1);   //加
     	 	v[x]=1-v[x];
     	 }
     	else
     	  cout<<find(en[x])-find(st[x]-1)<<endl;
     }
    return 0;
}

你可能感兴趣的:(题解,树状数组)