POJ3321 - Apple Tree

题目大意

有一颗苹果树,它有N个树叉,每个树叉最开始的时候都结了一个苹果,有时卡卡会从树上把某个苹果摘下来,有时没结苹果的树叉上又会长出苹果来,卡卡有时还想知道某个子树的总苹果数量有多少

题解

题目也是要求实现单点加减,区间求和的功能,赤裸裸的树状数组呀,不过此题给出的不是一个线性的序列,而是树形的,因此我们需要先进行预处理,把树转换为线性序列。用邻接表建立好树,然后对树进行重新编号,这个可以用DFS来实现,每个节点记录第一次访问和最后一次访问时的编号,假设为l和r,那么区间[l,r]之间的所有编号是以此节点为根节点的子树的各个节点的编号,这样就把树转化为线性结构了,之后就是用树状数组来处理了

代码:

#include<iostream>

#include<cstdio>

#include<cstring>

#define MAXN 100005

using namespace std;

typedef struct

{

    int adv;

    int next;

} NODE;

NODE edg[2*MAXN];

int head[MAXN],c[MAXN],low[MAXN],high[MAXN];

bool visit[MAXN];

int n,m,k,step=0;

int lowbit(int x)

{

    return x&-x;

}

int sum(int x)

{

    int ret=0;

    while(x>0)

    {

        ret+=c[x];

        x-=lowbit(x);

    }

    return ret;

}

void add(int x,int d)

{

    while(x<=n)

    {

        c[x]+=d;

        x+=lowbit(x);

    }

}

void addege(int u,int v)

{

    edg[k].adv=v;

    edg[k].next=head[u];

    head[u]=k++;

}

void dfs(int u)

{

    int i;

    low[u]=++step;

    visit[u]=true;

    for(i=head[u]; i!=-1; i=edg[i].next)

        if(!visit[edg[i].adv])

            dfs(edg[i].adv);

    high[u]=step;

}

int main(void)

{

    int i,u,v;

    bool f[MAXN];

    char ch;

    memset(head,-1,sizeof(head));

    memset(visit,false,sizeof(visit));

    memset(f,false,sizeof(f));

    scanf("%d",&n);

    k=1;

    for(i=1; i<n; i++)

    {

        scanf("%d%d",&u,&v);

        addege(u,v);

        add(i,1);

    }

    add(i,1);

    dfs(1);

    scanf("%d",&m);

    while(m--)

    {

        getchar();

        scanf("%c%d",&ch,&i);

        if(ch=='C')

        {

            if(!f[i])

            {

                add(low[i],-1);

                f[i]=true;

            }

            else

            {

                add(low[i],1);

                f[i]=false;

            }

        }

        else

            printf("%d\n",sum(high[i])-sum(low[i]-1));

    }

    return 0;

}

 

 

 

你可能感兴趣的:(apple)