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;
}

 

 

 

原文地址:https://www.cnblogs.com/zjbztianya/p/3036884.html